diff --git a/api/services/snapshot/v1/snapshots.pb.go b/api/services/snapshot/v1/snapshots.pb.go index 5770792ca..2758bf490 100644 --- a/api/services/snapshot/v1/snapshots.pb.go +++ b/api/services/snapshot/v1/snapshots.pb.go @@ -20,6 +20,8 @@ StatSnapshotRequest Info StatSnapshotResponse + UpdateSnapshotRequest + UpdateSnapshotResponse ListSnapshotsRequest ListSnapshotsResponse UsageRequest @@ -32,15 +34,22 @@ import fmt "fmt" import math "math" import _ "github.com/gogo/protobuf/gogoproto" import google_protobuf1 "github.com/golang/protobuf/ptypes/empty" +import google_protobuf2 "github.com/gogo/protobuf/types" +import _ "github.com/gogo/protobuf/types" import containerd_types "github.com/containerd/containerd/api/types" +import time "time" + import ( context "golang.org/x/net/context" grpc "google.golang.org/grpc" ) +import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + import strings "strings" import reflect "reflect" +import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" import io "io" @@ -48,6 +57,7 @@ import io "io" var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +var _ = time.Kitchen // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. @@ -86,6 +96,8 @@ type PrepareSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"` + // Labels are arbitrary data on snapshots. + Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *PrepareSnapshotRequest) Reset() { *m = PrepareSnapshotRequest{} } @@ -104,6 +116,8 @@ type ViewSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"` + // Labels are arbitrary data on snapshots. + Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *ViewSnapshotRequest) Reset() { *m = ViewSnapshotRequest{} } @@ -148,6 +162,8 @@ type CommitSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + // Labels are arbitrary data on snapshots. + Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *CommitSnapshotRequest) Reset() { *m = CommitSnapshotRequest{} } @@ -167,6 +183,12 @@ type Info struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` Kind Kind `protobuf:"varint,3,opt,name=kind,proto3,enum=containerd.services.snapshots.v1.Kind" json:"kind,omitempty"` + // CreatedAt provides the time at which the snapshot was created. + CreatedAt time.Time `protobuf:"bytes,4,opt,name=created_at,json=createdAt,stdtime" json:"created_at"` + // UpdatedAt provides the time the info was last updated. + UpdatedAt time.Time `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` + // Labels are arbitrary data on snapshots. + Labels map[string]string `protobuf:"bytes,6,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *Info) Reset() { *m = Info{} } @@ -181,13 +203,37 @@ func (m *StatSnapshotResponse) Reset() { *m = StatSnapshotRes func (*StatSnapshotResponse) ProtoMessage() {} func (*StatSnapshotResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{10} } +type UpdateSnapshotRequest struct { + Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` + Info Info `protobuf:"bytes,2,opt,name=info" json:"info"` + // UpdateMask specifies which fields to perform the update on. If empty, + // the operation applies to all fields. + // + // In info, Name, Parent, Kind, Created are immutable, + // other field may be updated using this mask. + // If no mask is provided, all mutable field are updated. + UpdateMask *google_protobuf2.FieldMask `protobuf:"bytes,3,opt,name=update_mask,json=updateMask" json:"update_mask,omitempty"` +} + +func (m *UpdateSnapshotRequest) Reset() { *m = UpdateSnapshotRequest{} } +func (*UpdateSnapshotRequest) ProtoMessage() {} +func (*UpdateSnapshotRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{11} } + +type UpdateSnapshotResponse struct { + Info Info `protobuf:"bytes,1,opt,name=info" json:"info"` +} + +func (m *UpdateSnapshotResponse) Reset() { *m = UpdateSnapshotResponse{} } +func (*UpdateSnapshotResponse) ProtoMessage() {} +func (*UpdateSnapshotResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{12} } + type ListSnapshotsRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` } func (m *ListSnapshotsRequest) Reset() { *m = ListSnapshotsRequest{} } func (*ListSnapshotsRequest) ProtoMessage() {} -func (*ListSnapshotsRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{11} } +func (*ListSnapshotsRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{13} } type ListSnapshotsResponse struct { Info []Info `protobuf:"bytes,1,rep,name=info" json:"info"` @@ -195,7 +241,7 @@ type ListSnapshotsResponse struct { func (m *ListSnapshotsResponse) Reset() { *m = ListSnapshotsResponse{} } func (*ListSnapshotsResponse) ProtoMessage() {} -func (*ListSnapshotsResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{12} } +func (*ListSnapshotsResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{14} } type UsageRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` @@ -204,7 +250,7 @@ type UsageRequest struct { func (m *UsageRequest) Reset() { *m = UsageRequest{} } func (*UsageRequest) ProtoMessage() {} -func (*UsageRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{13} } +func (*UsageRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{15} } type UsageResponse struct { Size_ int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` @@ -213,7 +259,7 @@ type UsageResponse struct { func (m *UsageResponse) Reset() { *m = UsageResponse{} } func (*UsageResponse) ProtoMessage() {} -func (*UsageResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{14} } +func (*UsageResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{16} } func init() { proto.RegisterType((*PrepareSnapshotRequest)(nil), "containerd.services.snapshots.v1.PrepareSnapshotRequest") @@ -227,6 +273,8 @@ func init() { proto.RegisterType((*StatSnapshotRequest)(nil), "containerd.services.snapshots.v1.StatSnapshotRequest") proto.RegisterType((*Info)(nil), "containerd.services.snapshots.v1.Info") proto.RegisterType((*StatSnapshotResponse)(nil), "containerd.services.snapshots.v1.StatSnapshotResponse") + proto.RegisterType((*UpdateSnapshotRequest)(nil), "containerd.services.snapshots.v1.UpdateSnapshotRequest") + proto.RegisterType((*UpdateSnapshotResponse)(nil), "containerd.services.snapshots.v1.UpdateSnapshotResponse") proto.RegisterType((*ListSnapshotsRequest)(nil), "containerd.services.snapshots.v1.ListSnapshotsRequest") proto.RegisterType((*ListSnapshotsResponse)(nil), "containerd.services.snapshots.v1.ListSnapshotsResponse") proto.RegisterType((*UsageRequest)(nil), "containerd.services.snapshots.v1.UsageRequest") @@ -251,6 +299,7 @@ type SnapshotsClient interface { Commit(ctx context.Context, in *CommitSnapshotRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) Remove(ctx context.Context, in *RemoveSnapshotRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) Stat(ctx context.Context, in *StatSnapshotRequest, opts ...grpc.CallOption) (*StatSnapshotResponse, error) + Update(ctx context.Context, in *UpdateSnapshotRequest, opts ...grpc.CallOption) (*UpdateSnapshotResponse, error) List(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (Snapshots_ListClient, error) Usage(ctx context.Context, in *UsageRequest, opts ...grpc.CallOption) (*UsageResponse, error) } @@ -317,6 +366,15 @@ func (c *snapshotsClient) Stat(ctx context.Context, in *StatSnapshotRequest, opt return out, nil } +func (c *snapshotsClient) Update(ctx context.Context, in *UpdateSnapshotRequest, opts ...grpc.CallOption) (*UpdateSnapshotResponse, error) { + out := new(UpdateSnapshotResponse) + err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Update", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *snapshotsClient) List(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (Snapshots_ListClient, error) { stream, err := grpc.NewClientStream(ctx, &_Snapshots_serviceDesc.Streams[0], c.cc, "/containerd.services.snapshots.v1.Snapshots/List", opts...) if err != nil { @@ -367,6 +425,7 @@ type SnapshotsServer interface { Commit(context.Context, *CommitSnapshotRequest) (*google_protobuf1.Empty, error) Remove(context.Context, *RemoveSnapshotRequest) (*google_protobuf1.Empty, error) Stat(context.Context, *StatSnapshotRequest) (*StatSnapshotResponse, error) + Update(context.Context, *UpdateSnapshotRequest) (*UpdateSnapshotResponse, error) List(*ListSnapshotsRequest, Snapshots_ListServer) error Usage(context.Context, *UsageRequest) (*UsageResponse, error) } @@ -483,6 +542,24 @@ func _Snapshots_Stat_Handler(srv interface{}, ctx context.Context, dec func(inte return interceptor(ctx, in, info, handler) } +func _Snapshots_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSnapshotRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SnapshotsServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.snapshots.v1.Snapshots/Update", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SnapshotsServer).Update(ctx, req.(*UpdateSnapshotRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Snapshots_List_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(ListSnapshotsRequest) if err := stream.RecvMsg(m); err != nil { @@ -550,6 +627,10 @@ var _Snapshots_serviceDesc = grpc.ServiceDesc{ MethodName: "Stat", Handler: _Snapshots_Stat_Handler, }, + { + MethodName: "Update", + Handler: _Snapshots_Update_Handler, + }, { MethodName: "Usage", Handler: _Snapshots_Usage_Handler, @@ -598,6 +679,23 @@ func (m *PrepareSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) i += copy(dAtA[i:], m.Parent) } + if len(m.Labels) > 0 { + for k, _ := range m.Labels { + dAtA[i] = 0x22 + i++ + v := m.Labels[k] + mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } return i, nil } @@ -664,6 +762,23 @@ func (m *ViewSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) i += copy(dAtA[i:], m.Parent) } + if len(m.Labels) > 0 { + for k, _ := range m.Labels { + dAtA[i] = 0x22 + i++ + v := m.Labels[k] + mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } return i, nil } @@ -820,6 +935,23 @@ func (m *CommitSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) i += copy(dAtA[i:], m.Key) } + if len(m.Labels) > 0 { + for k, _ := range m.Labels { + dAtA[i] = 0x22 + i++ + v := m.Labels[k] + mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } return i, nil } @@ -885,6 +1017,39 @@ func (m *Info) MarshalTo(dAtA []byte) (int, error) { i++ i = encodeVarintSnapshots(dAtA, i, uint64(m.Kind)) } + dAtA[i] = 0x22 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt))) + n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + dAtA[i] = 0x2a + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt))) + n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) + if err != nil { + return 0, err + } + i += n2 + if len(m.Labels) > 0 { + for k, _ := range m.Labels { + dAtA[i] = 0x32 + i++ + v := m.Labels[k] + mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } return i, nil } @@ -906,11 +1071,79 @@ func (m *StatSnapshotResponse) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) - n1, err := m.Info.MarshalTo(dAtA[i:]) + n3, err := m.Info.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n1 + i += n3 + return i, nil +} + +func (m *UpdateSnapshotRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpdateSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Snapshotter) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i += copy(dAtA[i:], m.Snapshotter) + } + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) + n4, err := m.Info.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n4 + if m.UpdateMask != nil { + dAtA[i] = 0x1a + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(m.UpdateMask.Size())) + n5, err := m.UpdateMask.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n5 + } + return i, nil +} + +func (m *UpdateSnapshotResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpdateSnapshotResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) + n6, err := m.Info.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n6 return i, nil } @@ -1068,6 +1301,14 @@ func (m *PrepareSnapshotRequest) Size() (n int) { if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) + } + } return n } @@ -1098,6 +1339,14 @@ func (m *ViewSnapshotRequest) Size() (n int) { if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) + } + } return n } @@ -1168,6 +1417,14 @@ func (m *CommitSnapshotRequest) Size() (n int) { if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) + } + } return n } @@ -1199,6 +1456,18 @@ func (m *Info) Size() (n int) { if m.Kind != 0 { n += 1 + sovSnapshots(uint64(m.Kind)) } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) + n += 1 + l + sovSnapshots(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) + n += 1 + l + sovSnapshots(uint64(l)) + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) + } + } return n } @@ -1210,6 +1479,30 @@ func (m *StatSnapshotResponse) Size() (n int) { return n } +func (m *UpdateSnapshotRequest) Size() (n int) { + var l int + _ = l + l = len(m.Snapshotter) + if l > 0 { + n += 1 + l + sovSnapshots(uint64(l)) + } + l = m.Info.Size() + n += 1 + l + sovSnapshots(uint64(l)) + if m.UpdateMask != nil { + l = m.UpdateMask.Size() + n += 1 + l + sovSnapshots(uint64(l)) + } + return n +} + +func (m *UpdateSnapshotResponse) Size() (n int) { + var l int + _ = l + l = m.Info.Size() + n += 1 + l + sovSnapshots(uint64(l)) + return n +} + func (m *ListSnapshotsRequest) Size() (n int) { var l int _ = l @@ -1275,10 +1568,21 @@ func (this *PrepareSnapshotRequest) String() string { if this == 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{`&PrepareSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, + `Labels:` + mapStringForLabels + `,`, `}`, }, "") return s @@ -1297,10 +1601,21 @@ func (this *ViewSnapshotRequest) String() string { if this == 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{`&ViewSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, + `Labels:` + mapStringForLabels + `,`, `}`, }, "") return s @@ -1351,10 +1666,21 @@ func (this *CommitSnapshotRequest) String() string { if this == 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{`&CommitSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `Labels:` + mapStringForLabels + `,`, `}`, }, "") return s @@ -1374,10 +1700,23 @@ func (this *Info) String() string { if this == 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{`&Info{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, + `CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `Labels:` + mapStringForLabels + `,`, `}`, }, "") return s @@ -1392,6 +1731,28 @@ func (this *StatSnapshotResponse) String() string { }, "") return s } +func (this *UpdateSnapshotRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&UpdateSnapshotRequest{`, + `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, + `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, + `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "google_protobuf2.FieldMask", 1) + `,`, + `}`, + }, "") + return s +} +func (this *UpdateSnapshotResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&UpdateSnapshotResponse{`, + `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} func (this *ListSnapshotsRequest) String() string { if this == nil { return "nil" @@ -1558,6 +1919,122 @@ func (m *PrepareSnapshotRequest) Unmarshal(dAtA []byte) error { } m.Parent = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + 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 ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + m.Labels[mapkey] = mapvalue + } else { + var mapvalue string + m.Labels[mapkey] = mapvalue + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) @@ -1776,6 +2253,122 @@ func (m *ViewSnapshotRequest) Unmarshal(dAtA []byte) error { } m.Parent = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + 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 ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + m.Labels[mapkey] = mapvalue + } else { + var mapvalue string + m.Labels[mapkey] = mapvalue + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) @@ -2291,6 +2884,122 @@ func (m *CommitSnapshotRequest) Unmarshal(dAtA []byte) error { } m.Key = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + 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 ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + m.Labels[mapkey] = mapvalue + } else { + var mapvalue string + m.Labels[mapkey] = mapvalue + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) @@ -2526,6 +3235,182 @@ func (m *Info) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + 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 ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + m.Labels[mapkey] = mapvalue + } else { + var mapvalue string + m.Labels[mapkey] = mapvalue + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) @@ -2627,6 +3512,228 @@ func (m *StatSnapshotResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *UpdateSnapshotRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdateSnapshotRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateSnapshotRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Snapshotter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Snapshotter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdateMask", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.UpdateMask == nil { + m.UpdateMask = &google_protobuf2.FieldMask{} + } + if err := m.UpdateMask.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSnapshots(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSnapshots + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpdateSnapshotResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdateSnapshotResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateSnapshotResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSnapshots(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSnapshots + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ListSnapshotsRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -3093,53 +4200,68 @@ func init() { } var fileDescriptorSnapshots = []byte{ - // 766 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x4e, 0xdb, 0x4a, - 0x18, 0x8d, 0xb1, 0x6f, 0xb8, 0x7c, 0x01, 0x6e, 0xee, 0x10, 0x42, 0xe4, 0x7b, 0xe5, 0x6b, 0x79, - 0x71, 0x85, 0xba, 0xb0, 0x81, 0xaa, 0x40, 0xcb, 0xa6, 0x24, 0x8d, 0xaa, 0x94, 0x02, 0x95, 0xf9, - 0x2b, 0x55, 0xa5, 0xca, 0x24, 0x43, 0xb0, 0xd2, 0xcc, 0xa4, 0xf1, 0x24, 0x28, 0x5d, 0x54, 0xed, - 0x0e, 0xe5, 0x1d, 0xb2, 0x6a, 0x9f, 0xa2, 0x4f, 0xc0, 0xb2, 0xcb, 0xae, 0xaa, 0x92, 0x27, 0xa9, - 0x66, 0xec, 0xfc, 0x50, 0x52, 0xc5, 0x04, 0xba, 0xfb, 0x3c, 0xdf, 0x9c, 0xf3, 0x9d, 0xcc, 0xb1, - 0xcf, 0x04, 0x72, 0x45, 0x97, 0x9d, 0xd4, 0x8e, 0xcc, 0x3c, 0x2d, 0x5b, 0x79, 0x4a, 0x98, 0xe3, - 0x12, 0x5c, 0x2d, 0xf4, 0x97, 0x4e, 0xc5, 0xb5, 0x3c, 0x5c, 0xad, 0xbb, 0x79, 0xec, 0x59, 0x1e, - 0x71, 0x2a, 0xde, 0x09, 0x65, 0x56, 0x7d, 0xb1, 0x5b, 0x7b, 0x66, 0xa5, 0x4a, 0x19, 0x45, 0x7a, - 0x0f, 0x64, 0x76, 0x00, 0x66, 0x6f, 0x53, 0x7d, 0x51, 0x4d, 0x14, 0x69, 0x91, 0x8a, 0xcd, 0x16, - 0xaf, 0x7c, 0x9c, 0xfa, 0x4f, 0x91, 0xd2, 0xe2, 0x6b, 0x6c, 0x89, 0xa7, 0xa3, 0xda, 0xb1, 0x85, - 0xcb, 0x15, 0xd6, 0x08, 0x9a, 0xcb, 0xa1, 0xf4, 0xb1, 0x46, 0x05, 0x7b, 0x56, 0x99, 0xd6, 0x08, - 0xf3, 0x71, 0x46, 0x01, 0x92, 0xcf, 0xaa, 0xb8, 0xe2, 0x54, 0xf1, 0x4e, 0xa0, 0xc0, 0xc6, 0x6f, - 0x6a, 0xd8, 0x63, 0x48, 0x87, 0x58, 0x47, 0x14, 0xc3, 0xd5, 0x94, 0xa4, 0x4b, 0xf3, 0x13, 0x76, - 0xff, 0x12, 0x8a, 0x83, 0x5c, 0xc2, 0x8d, 0xd4, 0x98, 0xe8, 0xf0, 0x12, 0x25, 0x21, 0xca, 0xa9, - 0x08, 0x4b, 0xc9, 0x62, 0x31, 0x78, 0x32, 0x9e, 0xc0, 0xdc, 0x95, 0x29, 0x5e, 0x85, 0x12, 0x0f, - 0x23, 0x0b, 0xa2, 0x42, 0x8f, 0x97, 0x92, 0x74, 0x79, 0x3e, 0xb6, 0x34, 0x67, 0xf6, 0x1d, 0x8f, - 0xd0, 0x6b, 0x6e, 0xf2, 0xbe, 0x1d, 0x6c, 0x33, 0x1c, 0x98, 0xd9, 0x77, 0xf1, 0xe9, 0xef, 0x94, - 0xfb, 0x18, 0x12, 0x97, 0x47, 0x8c, 0xaa, 0x35, 0x03, 0x53, 0x62, 0xc1, 0xbb, 0x81, 0x4a, 0x63, - 0x1d, 0xa6, 0x3b, 0x24, 0xa3, 0xea, 0xd8, 0x80, 0x59, 0x1b, 0x97, 0x69, 0xfd, 0x36, 0x4c, 0x36, - 0x5e, 0xc1, 0x6c, 0x86, 0x96, 0xcb, 0x2e, 0xbb, 0x3e, 0x19, 0x02, 0x85, 0x38, 0x65, 0x1c, 0xb0, - 0x89, 0xba, 0x33, 0x40, 0xee, 0x0d, 0xc8, 0xc1, 0xcc, 0x0e, 0x73, 0xd8, 0x6d, 0x68, 0x25, 0xa0, - 0xe4, 0xc8, 0x31, 0xed, 0x0e, 0x96, 0xfa, 0x06, 0xf7, 0xdc, 0x1f, 0xeb, 0x77, 0x1f, 0x3d, 0x00, - 0xa5, 0xe4, 0x92, 0x82, 0x50, 0x34, 0xbd, 0xf4, 0xbf, 0x39, 0xec, 0x73, 0x35, 0x37, 0x5c, 0x52, - 0xb0, 0x05, 0xc6, 0x78, 0x0e, 0x89, 0xcb, 0xd2, 0x03, 0xc7, 0x1e, 0x82, 0xe2, 0x92, 0x63, 0x2a, - 0xe6, 0xc7, 0xc2, 0x70, 0x72, 0xd5, 0x69, 0xe5, 0xfc, 0xdb, 0x7f, 0x11, 0x5b, 0x20, 0x8d, 0x55, - 0x48, 0x3c, 0x75, 0xbd, 0x2e, 0x73, 0xf8, 0x37, 0xca, 0x38, 0x84, 0xd9, 0x9f, 0x90, 0x57, 0x44, - 0xc9, 0x23, 0x8a, 0x4a, 0xc3, 0xe4, 0x9e, 0xe7, 0x14, 0xf1, 0x4d, 0x2c, 0x5a, 0x83, 0xa9, 0x80, - 0x23, 0x90, 0x85, 0x40, 0xf1, 0xdc, 0xb7, 0xbe, 0x57, 0xb2, 0x2d, 0x6a, 0xee, 0x95, 0x4b, 0x68, - 0x01, 0x7b, 0x02, 0x29, 0xdb, 0xc1, 0xd3, 0x9d, 0x33, 0x09, 0x14, 0x7e, 0xfc, 0xe8, 0x5f, 0x18, - 0xdf, 0xdb, 0xda, 0xd8, 0xda, 0x3e, 0xd8, 0x8a, 0x47, 0xd4, 0xbf, 0x9a, 0x2d, 0x3d, 0xc6, 0x97, - 0xf7, 0x48, 0x89, 0xd0, 0x53, 0x82, 0x92, 0xa0, 0xec, 0xe7, 0xb2, 0x07, 0x71, 0x49, 0x9d, 0x6c, - 0xb6, 0xf4, 0x3f, 0x79, 0x8b, 0x7f, 0xe0, 0x48, 0x85, 0xe8, 0x7a, 0x66, 0x37, 0xb7, 0x9f, 0x8d, - 0x8f, 0xa9, 0xd3, 0xcd, 0x96, 0x0e, 0xbc, 0xb3, 0x9e, 0x67, 0x6e, 0x1d, 0x23, 0x1d, 0x26, 0x32, - 0xdb, 0x9b, 0x9b, 0xb9, 0xdd, 0xdd, 0xec, 0xa3, 0xb8, 0xac, 0xfe, 0xdd, 0x6c, 0xe9, 0x53, 0xbc, - 0xed, 0xbf, 0xfb, 0x0c, 0x17, 0xd4, 0xc9, 0xb3, 0x8f, 0x5a, 0xe4, 0xf3, 0x27, 0x4d, 0x28, 0x58, - 0xfa, 0x30, 0x0e, 0x13, 0xdd, 0x33, 0x46, 0xef, 0x60, 0x3c, 0x48, 0x3c, 0xb4, 0x3a, 0xfc, 0x60, - 0x07, 0x47, 0xb0, 0x7a, 0x7f, 0x04, 0x64, 0x70, 0x88, 0x35, 0x50, 0xc4, 0x2f, 0xbc, 0x37, 0x9c, - 0x62, 0x40, 0x9a, 0xaa, 0xcb, 0xd7, 0x85, 0x05, 0x63, 0x4b, 0x10, 0xf5, 0xb3, 0x0a, 0x59, 0xc3, - 0x19, 0x2e, 0x45, 0xa3, 0xba, 0x10, 0x1e, 0x10, 0x0c, 0x3b, 0x84, 0xa8, 0x6f, 0x06, 0x5a, 0x19, - 0x8e, 0x1d, 0x18, 0x59, 0x6a, 0xd2, 0xf4, 0x2f, 0x55, 0xb3, 0x73, 0xa9, 0x9a, 0x59, 0x7e, 0xa9, - 0x72, 0x6a, 0x3f, 0x30, 0xc3, 0x50, 0x0f, 0x8c, 0xd6, 0x5f, 0x52, 0xd7, 0x40, 0xe1, 0x11, 0x11, - 0xc6, 0x99, 0x01, 0x29, 0x18, 0xc6, 0x99, 0x81, 0x09, 0xd4, 0x00, 0x85, 0xa7, 0x00, 0x0a, 0x81, - 0x1f, 0x94, 0x33, 0xea, 0xca, 0xb5, 0x71, 0xfe, 0xe0, 0x05, 0x09, 0x9d, 0xc0, 0x1f, 0xe2, 0x0b, - 0x47, 0xe6, 0x70, 0x8e, 0xfe, 0x38, 0x51, 0xad, 0xd0, 0xfb, 0xfd, 0x59, 0xe9, 0x97, 0xe7, 0x17, - 0x5a, 0xe4, 0xeb, 0x85, 0x16, 0x79, 0xdf, 0xd6, 0xa4, 0xf3, 0xb6, 0x26, 0x7d, 0x69, 0x6b, 0xd2, - 0xf7, 0xb6, 0x26, 0xbd, 0x48, 0x8f, 0xfc, 0xff, 0x6d, 0xad, 0x53, 0x1f, 0x45, 0x85, 0x93, 0x77, - 0x7f, 0x04, 0x00, 0x00, 0xff, 0xff, 0x51, 0x4b, 0x27, 0x3b, 0x0c, 0x0a, 0x00, 0x00, + // 1004 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1a, 0x47, + 0x14, 0xf7, 0xc0, 0x1a, 0xc7, 0x0f, 0xdb, 0xa5, 0x13, 0x4c, 0xd0, 0xb6, 0xc2, 0x2b, 0x0e, 0x95, + 0xd5, 0xc3, 0x6e, 0x42, 0xd5, 0xc4, 0x89, 0x2f, 0x05, 0x42, 0x2b, 0xe2, 0xd8, 0xa9, 0x36, 0xb6, + 0x53, 0xa7, 0x91, 0xa2, 0x35, 0x8c, 0xf1, 0x0a, 0x76, 0x97, 0x32, 0x03, 0x11, 0xad, 0x54, 0xf5, + 0x18, 0xf9, 0xd4, 0x2f, 0xe0, 0x53, 0xfb, 0x21, 0xaa, 0x7e, 0x02, 0x1f, 0x7b, 0xec, 0xa9, 0x6d, + 0xfc, 0x25, 0x7a, 0xea, 0x1f, 0xcd, 0xec, 0x2c, 0x60, 0x4c, 0xc5, 0xb2, 0xa1, 0xb7, 0xb7, 0x33, + 0xf3, 0xde, 0xfb, 0xbd, 0xdf, 0x9b, 0xf7, 0xde, 0x2c, 0x54, 0x1b, 0x36, 0x3b, 0xed, 0x1e, 0xeb, + 0x35, 0xcf, 0x31, 0x6a, 0x9e, 0xcb, 0x2c, 0xdb, 0x25, 0x9d, 0xfa, 0xa8, 0x68, 0xb5, 0x6d, 0x83, + 0x92, 0x4e, 0xcf, 0xae, 0x11, 0x6a, 0x50, 0xd7, 0x6a, 0xd3, 0x53, 0x8f, 0x19, 0xbd, 0x3b, 0x03, + 0x99, 0xea, 0xed, 0x8e, 0xc7, 0x3c, 0xac, 0x0d, 0x95, 0xf4, 0x40, 0x41, 0x1f, 0x1e, 0xea, 0xdd, + 0x51, 0xd3, 0x0d, 0xaf, 0xe1, 0x89, 0xc3, 0x06, 0x97, 0x7c, 0x3d, 0xf5, 0xbd, 0x86, 0xe7, 0x35, + 0x5a, 0xc4, 0x10, 0x5f, 0xc7, 0xdd, 0x13, 0x83, 0x38, 0x6d, 0xd6, 0x97, 0x9b, 0xda, 0xf8, 0xe6, + 0x89, 0x4d, 0x5a, 0xf5, 0x97, 0x8e, 0x45, 0x9b, 0xf2, 0xc4, 0xc6, 0xf8, 0x09, 0x66, 0x3b, 0x84, + 0x32, 0xcb, 0x69, 0xcb, 0x03, 0x77, 0x43, 0x85, 0xc8, 0xfa, 0x6d, 0x42, 0x0d, 0xc7, 0xeb, 0xba, + 0xcc, 0xd7, 0xcb, 0xff, 0x85, 0x20, 0xf3, 0x79, 0x87, 0xb4, 0xad, 0x0e, 0x79, 0x2a, 0xa3, 0x30, + 0xc9, 0x57, 0x5d, 0x42, 0x19, 0xd6, 0x20, 0x19, 0x04, 0xc6, 0x48, 0x27, 0x8b, 0x34, 0xb4, 0xb9, + 0x6c, 0x8e, 0x2e, 0xe1, 0x14, 0xc4, 0x9b, 0xa4, 0x9f, 0x8d, 0x89, 0x1d, 0x2e, 0xe2, 0x0c, 0x24, + 0xb8, 0x29, 0x97, 0x65, 0xe3, 0x62, 0x51, 0x7e, 0xe1, 0x17, 0x90, 0x68, 0x59, 0xc7, 0xa4, 0x45, + 0xb3, 0x8a, 0x16, 0xdf, 0x4c, 0x16, 0x1e, 0xea, 0xd3, 0x78, 0xd4, 0x27, 0xa3, 0xd2, 0x1f, 0x0b, + 0x33, 0x15, 0x97, 0x75, 0xfa, 0xa6, 0xb4, 0xa9, 0xde, 0x87, 0xe4, 0xc8, 0x72, 0x00, 0x0b, 0x0d, + 0x61, 0xa5, 0x61, 0xb1, 0x67, 0xb5, 0xba, 0x44, 0x42, 0xf5, 0x3f, 0x1e, 0xc4, 0xb6, 0x50, 0xfe, + 0x11, 0xdc, 0xba, 0xe6, 0x88, 0xb6, 0x3d, 0x97, 0x12, 0x6c, 0x40, 0x42, 0x30, 0x45, 0xb3, 0x48, + 0x60, 0xbe, 0x35, 0x8a, 0x59, 0x30, 0xa9, 0xef, 0xf2, 0x7d, 0x53, 0x1e, 0xcb, 0xff, 0x89, 0xe0, + 0xe6, 0xa1, 0x4d, 0x5e, 0xfd, 0x9f, 0x44, 0x1e, 0x8d, 0x11, 0x59, 0x9c, 0x4e, 0xe4, 0x04, 0x48, + 0xf3, 0x66, 0xf1, 0x33, 0x48, 0x5f, 0xf5, 0x12, 0x95, 0xc2, 0x32, 0xac, 0x8a, 0x05, 0xfa, 0x16, + 0xdc, 0xe5, 0x8b, 0xb0, 0x16, 0x18, 0x89, 0x8a, 0x63, 0x07, 0xd6, 0x4d, 0xe2, 0x78, 0xbd, 0x79, + 0x14, 0x05, 0xbf, 0x17, 0xeb, 0x65, 0xcf, 0x71, 0x6c, 0x36, 0xbb, 0x35, 0x0c, 0x8a, 0x6b, 0x39, + 0x01, 0xe5, 0x42, 0x0e, 0x3c, 0xc4, 0x87, 0x99, 0xf9, 0x72, 0xec, 0x56, 0x94, 0xa7, 0xdf, 0x8a, + 0x89, 0x80, 0xe6, 0x7d, 0x2f, 0xaa, 0x70, 0xf3, 0x29, 0xb3, 0xd8, 0x3c, 0x48, 0xfc, 0x27, 0x06, + 0x4a, 0xd5, 0x3d, 0xf1, 0x06, 0x8c, 0xa0, 0x11, 0x46, 0x86, 0xd5, 0x12, 0xbb, 0x52, 0x2d, 0x0f, + 0x40, 0x69, 0xda, 0x6e, 0x5d, 0x50, 0xb5, 0x56, 0xf8, 0x60, 0x3a, 0x2b, 0x3b, 0xb6, 0x5b, 0x37, + 0x85, 0x0e, 0x2e, 0x03, 0xd4, 0x3a, 0xc4, 0x62, 0xa4, 0xfe, 0xd2, 0x62, 0x59, 0x45, 0x43, 0x9b, + 0xc9, 0x82, 0xaa, 0xfb, 0x7d, 0x58, 0x0f, 0xfa, 0xb0, 0xbe, 0x1f, 0xf4, 0xe1, 0xd2, 0x8d, 0x8b, + 0xdf, 0x36, 0x16, 0xbe, 0xff, 0x7d, 0x03, 0x99, 0xcb, 0x52, 0xaf, 0xc8, 0xb8, 0x91, 0x6e, 0xbb, + 0x1e, 0x18, 0x59, 0x9c, 0xc5, 0x88, 0xd4, 0x2b, 0x32, 0xfc, 0x68, 0x90, 0xdd, 0x84, 0xc8, 0x6e, + 0x61, 0x7a, 0x1c, 0x9c, 0xa9, 0x79, 0x27, 0xf3, 0x0b, 0x48, 0x5f, 0x4d, 0xa6, 0x2c, 0xae, 0x4f, + 0x40, 0xb1, 0xdd, 0x13, 0x4f, 0x18, 0x49, 0x86, 0x21, 0x99, 0x83, 0x2b, 0x29, 0x3c, 0x52, 0x53, + 0x68, 0xe6, 0x7f, 0x42, 0xb0, 0x7e, 0x20, 0xc2, 0x9d, 0xfd, 0xa6, 0x04, 0xde, 0x63, 0x51, 0xbd, + 0xe3, 0x6d, 0x48, 0xfa, 0x5c, 0x8b, 0x81, 0x2b, 0xee, 0xca, 0xa4, 0x24, 0x7d, 0xca, 0x67, 0xf2, + 0xae, 0x45, 0x9b, 0xa6, 0x4c, 0x29, 0x97, 0xf3, 0xcf, 0x21, 0x33, 0x8e, 0x7c, 0x6e, 0xb4, 0x6c, + 0x41, 0xfa, 0xb1, 0x4d, 0x07, 0x84, 0x87, 0xef, 0x89, 0xf9, 0x23, 0x58, 0x1f, 0xd3, 0xbc, 0x06, + 0x2a, 0x1e, 0x11, 0x54, 0x09, 0x56, 0x0e, 0xa8, 0xd5, 0x20, 0x6f, 0x53, 0xcb, 0xdb, 0xb0, 0x2a, + 0x6d, 0x48, 0x58, 0x18, 0x14, 0x6a, 0x7f, 0xed, 0xd7, 0x74, 0xdc, 0x14, 0x32, 0xaf, 0x69, 0xdb, + 0xf5, 0xea, 0x84, 0x0a, 0xcd, 0xb8, 0x29, 0xbf, 0x3e, 0x7c, 0x8d, 0x40, 0xe1, 0x65, 0x8a, 0xdf, + 0x87, 0xa5, 0x83, 0xbd, 0x9d, 0xbd, 0x27, 0xcf, 0xf6, 0x52, 0x0b, 0xea, 0x3b, 0x67, 0xe7, 0x5a, + 0x92, 0x2f, 0x1f, 0xb8, 0x4d, 0xd7, 0x7b, 0xe5, 0xe2, 0x0c, 0x28, 0x87, 0xd5, 0xca, 0xb3, 0x14, + 0x52, 0x57, 0xce, 0xce, 0xb5, 0x1b, 0x7c, 0x8b, 0x8f, 0x28, 0xac, 0x42, 0xa2, 0x58, 0xde, 0xaf, + 0x1e, 0x56, 0x52, 0x31, 0x75, 0xed, 0xec, 0x5c, 0x03, 0xbe, 0x53, 0xac, 0x31, 0xbb, 0x47, 0xb0, + 0x06, 0xcb, 0xe5, 0x27, 0xbb, 0xbb, 0xd5, 0xfd, 0xfd, 0xca, 0xc3, 0x54, 0x5c, 0x7d, 0xf7, 0xec, + 0x5c, 0x5b, 0xe5, 0xdb, 0x7e, 0xaf, 0x64, 0xa4, 0xae, 0xae, 0xbc, 0xfe, 0x21, 0xb7, 0xf0, 0xf3, + 0x8f, 0x39, 0x81, 0xa0, 0xf0, 0xf7, 0x12, 0x2c, 0x0f, 0x38, 0xc6, 0xdf, 0xc2, 0x92, 0x7c, 0x4a, + 0xe0, 0xad, 0xa8, 0xcf, 0x1b, 0xf5, 0x7e, 0x04, 0x4d, 0x49, 0x62, 0x17, 0x14, 0x11, 0xe1, 0xc7, + 0x91, 0x9e, 0x04, 0xea, 0xdd, 0x59, 0xd5, 0xa4, 0xdb, 0x26, 0x24, 0xfc, 0x69, 0x8b, 0x8d, 0xe9, + 0x16, 0xae, 0x0c, 0x77, 0xf5, 0x76, 0x78, 0x05, 0xe9, 0xec, 0x08, 0x12, 0x7e, 0x32, 0xf0, 0xbd, + 0x88, 0x23, 0x4e, 0xcd, 0x5c, 0xab, 0xec, 0x0a, 0x7f, 0x8a, 0x73, 0xd3, 0xfe, 0xc8, 0x0f, 0x63, + 0x7a, 0xe2, 0xe3, 0xe0, 0x3f, 0x4d, 0x77, 0x41, 0xe1, 0x9d, 0x33, 0x4c, 0x66, 0x26, 0x8c, 0xcb, + 0x30, 0x99, 0x99, 0xd8, 0x98, 0xbf, 0x81, 0x84, 0xdf, 0x9b, 0xc2, 0x44, 0x34, 0xb1, 0xff, 0xaa, + 0x5b, 0xb3, 0x2b, 0x4a, 0xe7, 0x7d, 0x50, 0x78, 0x0b, 0xc2, 0x21, 0xc0, 0x4f, 0x6a, 0x72, 0xea, + 0xbd, 0x99, 0xf5, 0x7c, 0xc7, 0xb7, 0x11, 0x3e, 0x85, 0x45, 0xd1, 0x5e, 0xb0, 0x1e, 0x02, 0xfd, + 0x48, 0x2f, 0x53, 0x8d, 0xd0, 0xe7, 0x7d, 0x5f, 0xa5, 0x17, 0x17, 0x6f, 0x72, 0x0b, 0xbf, 0xbe, + 0xc9, 0x2d, 0x7c, 0x77, 0x99, 0x43, 0x17, 0x97, 0x39, 0xf4, 0xcb, 0x65, 0x0e, 0xfd, 0x71, 0x99, + 0x43, 0xcf, 0x4b, 0x91, 0x7f, 0x39, 0xb7, 0x03, 0xf9, 0x38, 0x21, 0xae, 0xd1, 0x47, 0xff, 0x06, + 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0x35, 0xc8, 0xbf, 0x0e, 0x00, 0x00, } diff --git a/api/services/snapshot/v1/snapshots.proto b/api/services/snapshot/v1/snapshots.proto index 3f5180dc1..af3930ffb 100644 --- a/api/services/snapshot/v1/snapshots.proto +++ b/api/services/snapshot/v1/snapshots.proto @@ -4,6 +4,8 @@ package containerd.services.snapshots.v1; import "gogoproto/gogo.proto"; import "google/protobuf/empty.proto"; +import "google/protobuf/field_mask.proto"; +import "google/protobuf/timestamp.proto"; import "github.com/containerd/containerd/api/types/mount.proto"; option go_package = "github.com/containerd/containerd/api/services/snapshot/v1;snapshot"; @@ -16,6 +18,7 @@ service Snapshots { rpc Commit(CommitSnapshotRequest) returns (google.protobuf.Empty); rpc Remove(RemoveSnapshotRequest) returns (google.protobuf.Empty); rpc Stat(StatSnapshotRequest) returns (StatSnapshotResponse); + rpc Update(UpdateSnapshotRequest) returns (UpdateSnapshotResponse); rpc List(ListSnapshotsRequest) returns (stream ListSnapshotsResponse); rpc Usage(UsageRequest) returns (UsageResponse); } @@ -24,6 +27,9 @@ message PrepareSnapshotRequest { string snapshotter = 1; string key = 2; string parent = 3; + + // Labels are arbitrary data on snapshots. + map labels = 4; } message PrepareSnapshotResponse { @@ -34,6 +40,9 @@ message ViewSnapshotRequest { string snapshotter = 1; string key = 2; string parent = 3; + + // Labels are arbitrary data on snapshots. + map labels = 4; } message ViewSnapshotResponse { @@ -58,6 +67,9 @@ message CommitSnapshotRequest { string snapshotter = 1; string name = 2; string key = 3; + + // Labels are arbitrary data on snapshots. + map labels = 4; } message StatSnapshotRequest { @@ -79,12 +91,38 @@ message Info { string name = 1; string parent = 2; Kind kind = 3; + + // CreatedAt provides the time at which the snapshot was created. + google.protobuf.Timestamp created_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + + // UpdatedAt provides the time the info was last updated. + google.protobuf.Timestamp updated_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + + // Labels are arbitrary data on snapshots. + map labels = 6; } message StatSnapshotResponse { Info info = 1 [(gogoproto.nullable) = false]; } +message UpdateSnapshotRequest { + string snapshotter = 1; + Info info = 2 [(gogoproto.nullable) = false]; + + // UpdateMask specifies which fields to perform the update on. If empty, + // the operation applies to all fields. + // + // In info, Name, Parent, Kind, Created are immutable, + // other field may be updated using this mask. + // If no mask is provided, all mutable field are updated. + google.protobuf.FieldMask update_mask = 3; +} + +message UpdateSnapshotResponse { + Info info = 1 [(gogoproto.nullable) = false]; +} + message ListSnapshotsRequest{ string snapshotter = 1; } diff --git a/metadata/helpers.go b/metadata/boltutil/helpers.go similarity index 58% rename from metadata/helpers.go rename to metadata/boltutil/helpers.go index 063a0a54b..b713132dc 100644 --- a/metadata/helpers.go +++ b/metadata/boltutil/helpers.go @@ -1,4 +1,4 @@ -package metadata +package boltutil import ( "time" @@ -7,19 +7,36 @@ import ( "github.com/pkg/errors" ) -func readLabels(m map[string]string, bkt *bolt.Bucket) error { - return bkt.ForEach(func(k, v []byte) error { - m[string(k)] = string(v) +var ( + bucketKeyLabels = []byte("labels") + bucketKeyCreatedAt = []byte("createdat") + bucketKeyUpdatedAt = []byte("updatedat") +) + +// ReadLabels reads the labels key from the bucket +// Uses the key "labels" +func ReadLabels(bkt *bolt.Bucket) (map[string]string, error) { + lbkt := bkt.Bucket(bucketKeyLabels) + if lbkt == nil { + return nil, nil + } + labels := map[string]string{} + if err := lbkt.ForEach(func(k, v []byte) error { + labels[string(k)] = string(v) return nil - }) + }); err != nil { + return nil, err + } + return labels, nil } -// writeLabels will write a new labels bucket to the provided bucket at key +// WriteLabels will write a new labels bucket to the provided bucket at key // bucketKeyLabels, replacing the contents of the bucket with the provided map. // // The provide map labels will be modified to have the final contents of the // bucket. Typically, this removes zero-value entries. -func writeLabels(bkt *bolt.Bucket, labels map[string]string) error { +// Uses the key "labels" +func WriteLabels(bkt *bolt.Bucket, labels map[string]string) error { // Remove existing labels to keep from merging if lbkt := bkt.Bucket(bucketKeyLabels); lbkt != nil { if err := bkt.DeleteBucket(bucketKeyLabels); err != nil { @@ -50,7 +67,9 @@ func writeLabels(bkt *bolt.Bucket, labels map[string]string) error { return nil } -func readTimestamps(created, updated *time.Time, bkt *bolt.Bucket) error { +// ReadTimestamps reads created and updated timestamps from a bucket. +// Uses keys "createdat" and "updatedat" +func ReadTimestamps(bkt *bolt.Bucket, created, updated *time.Time) error { for _, f := range []struct { b []byte t *time.Time @@ -68,7 +87,9 @@ func readTimestamps(created, updated *time.Time, bkt *bolt.Bucket) error { return nil } -func writeTimestamps(bkt *bolt.Bucket, created, updated time.Time) error { +// WriteTimestamps writes created and updated timestamps to a bucket. +// Uses keys "createdat" and "updatedat" +func WriteTimestamps(bkt *bolt.Bucket, created, updated time.Time) error { createdAt, err := created.MarshalBinary() if err != nil { return err diff --git a/metadata/buckets.go b/metadata/buckets.go index 0ba3126bb..4bcfb203c 100644 --- a/metadata/buckets.go +++ b/metadata/buckets.go @@ -41,16 +41,14 @@ var ( bucketKeyDigest = []byte("digest") bucketKeyMediaType = []byte("mediatype") bucketKeySize = []byte("size") - bucketKeyLabels = []byte("labels") bucketKeyImage = []byte("image") bucketKeyRuntime = []byte("runtime") bucketKeyName = []byte("name") + bucketKeyParent = []byte("parent") bucketKeyOptions = []byte("options") bucketKeySpec = []byte("spec") bucketKeyRootFS = []byte("rootfs") bucketKeyTarget = []byte("target") - bucketKeyCreatedAt = []byte("createdat") - bucketKeyUpdatedAt = []byte("updatedat") ) func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket { diff --git a/metadata/containers.go b/metadata/containers.go index a951066ba..6061cd48f 100644 --- a/metadata/containers.go +++ b/metadata/containers.go @@ -10,6 +10,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" "github.com/containerd/containerd/identifiers" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/namespaces" "github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/types" @@ -206,6 +207,16 @@ func (s *containerStore) Delete(ctx context.Context, id string) error { } func readContainer(container *containers.Container, bkt *bolt.Bucket) error { + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err + } + container.Labels = labels + + if err := boltutil.ReadTimestamps(bkt, &container.CreatedAt, &container.UpdatedAt); err != nil { + return err + } + return bkt.ForEach(func(k, v []byte) error { switch string(k) { case string(bucketKeyImage): @@ -239,24 +250,7 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error { container.Spec = &any case string(bucketKeyRootFS): container.RootFS = string(v) - case string(bucketKeyCreatedAt): - if err := container.CreatedAt.UnmarshalBinary(v); err != nil { - return err - } - case string(bucketKeyUpdatedAt): - if err := container.UpdatedAt.UnmarshalBinary(v); err != nil { - return err - } - case string(bucketKeyLabels): - lbkt := bkt.Bucket(bucketKeyLabels) - if lbkt == nil { - return nil - } - container.Labels = map[string]string{} - if err := readLabels(container.Labels, lbkt); err != nil { - return err - } } return nil @@ -264,7 +258,7 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error { } func writeContainer(bkt *bolt.Bucket, container *containers.Container) error { - if err := writeTimestamps(bkt, container.CreatedAt, container.UpdatedAt); err != nil { + if err := boltutil.WriteTimestamps(bkt, container.CreatedAt, container.UpdatedAt); err != nil { return err } @@ -314,5 +308,5 @@ func writeContainer(bkt *bolt.Bucket, container *containers.Container) error { } } - return writeLabels(bkt, container.Labels) + return boltutil.WriteLabels(bkt, container.Labels) } diff --git a/metadata/content.go b/metadata/content.go index 811a91912..24b69d090 100644 --- a/metadata/content.go +++ b/metadata/content.go @@ -11,6 +11,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/namespaces" digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" @@ -390,24 +391,18 @@ func (nw *namespacedWriter) commit(tx *bolt.Tx, size int64, expected digest.Dige return err } + commitTime := time.Now().UTC() + sizeEncoded, err := encodeSize(size) if err != nil { return err } - timeEncoded, err := time.Now().UTC().MarshalBinary() - if err != nil { + if err := boltutil.WriteTimestamps(bkt, commitTime, commitTime); err != nil { return err } - - for _, v := range [][2][]byte{ - {bucketKeyCreatedAt, timeEncoded}, - {bucketKeyUpdatedAt, timeEncoded}, - {bucketKeySize, sizeEncoded}, - } { - if err := bkt.Put(v[0], v[1]); err != nil { - return err - } + if err := bkt.Put(bucketKeySize, sizeEncoded); err != nil { + return err } return nil @@ -451,17 +446,15 @@ func (cs *contentStore) checkAccess(ctx context.Context, dgst digest.Digest) err } func readInfo(info *content.Info, bkt *bolt.Bucket) error { - if err := readTimestamps(&info.CreatedAt, &info.UpdatedAt, bkt); err != nil { + if err := boltutil.ReadTimestamps(bkt, &info.CreatedAt, &info.UpdatedAt); err != nil { return err } - lbkt := bkt.Bucket(bucketKeyLabels) - if lbkt != nil { - info.Labels = map[string]string{} - if err := readLabels(info.Labels, lbkt); err != nil { - return err - } + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err } + info.Labels = labels if v := bkt.Get(bucketKeySize); len(v) > 0 { info.Size, _ = binary.Varint(v) @@ -471,11 +464,11 @@ func readInfo(info *content.Info, bkt *bolt.Bucket) error { } func writeInfo(info *content.Info, bkt *bolt.Bucket) error { - if err := writeTimestamps(bkt, info.CreatedAt, info.UpdatedAt); err != nil { + if err := boltutil.WriteTimestamps(bkt, info.CreatedAt, info.UpdatedAt); err != nil { return err } - if err := writeLabels(bkt, info.Labels); err != nil { + if err := boltutil.WriteLabels(bkt, info.Labels); err != nil { return errors.Wrapf(err, "writing labels for info %v", info.Digest) } diff --git a/metadata/images.go b/metadata/images.go index 1815af396..a44b3a7f4 100644 --- a/metadata/images.go +++ b/metadata/images.go @@ -11,6 +11,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/namespaces" digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" @@ -191,17 +192,15 @@ func (s *imageStore) Delete(ctx context.Context, name string) error { } func readImage(image *images.Image, bkt *bolt.Bucket) error { - if err := readTimestamps(&image.CreatedAt, &image.UpdatedAt, bkt); err != nil { + if err := boltutil.ReadTimestamps(bkt, &image.CreatedAt, &image.UpdatedAt); err != nil { return err } - lbkt := bkt.Bucket(bucketKeyLabels) - if lbkt != nil { - image.Labels = map[string]string{} - if err := readLabels(image.Labels, lbkt); err != nil { - return err - } + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err } + image.Labels = labels tbkt := bkt.Bucket(bucketKeyTarget) if tbkt == nil { @@ -228,11 +227,11 @@ func readImage(image *images.Image, bkt *bolt.Bucket) error { } func writeImage(bkt *bolt.Bucket, image *images.Image) error { - if err := writeTimestamps(bkt, image.CreatedAt, image.UpdatedAt); err != nil { + if err := boltutil.WriteTimestamps(bkt, image.CreatedAt, image.UpdatedAt); err != nil { return err } - if err := writeLabels(bkt, image.Labels); err != nil { + if err := boltutil.WriteLabels(bkt, image.Labels); err != nil { return errors.Wrapf(err, "writing labels for image %v", image.Name) } diff --git a/metadata/snapshot.go b/metadata/snapshot.go index f2267ec53..708843fa0 100644 --- a/metadata/snapshot.go +++ b/metadata/snapshot.go @@ -4,9 +4,11 @@ import ( "context" "fmt" "strings" + "time" "github.com/boltdb/bolt" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshot" @@ -46,7 +48,11 @@ func getKey(tx *bolt.Tx, ns, name, key string) string { if bkt == nil { return "" } - v := bkt.Get([]byte(key)) + bkt = bkt.Bucket([]byte(key)) + if bkt == nil { + return "" + } + v := bkt.Get(bucketKeyName) if len(v) == 0 { return "" } @@ -74,20 +80,144 @@ func (s *snapshotter) resolveKey(ctx context.Context, key string) (string, error } func (s *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, error) { - bkey, err := s.resolveKey(ctx, key) + ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return snapshot.Info{}, err } + + var ( + bkey string + local = snapshot.Info{ + Name: key, + } + ) + if err := view(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getSnapshotterBucket(tx, ns, s.name) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) + } + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) + } + local.Labels, err = boltutil.ReadLabels(sbkt) + if err != nil { + return errors.Wrap(err, "failed to read labels") + } + if err := boltutil.ReadTimestamps(sbkt, &local.Created, &local.Updated); err != nil { + return errors.Wrap(err, "failed to read timestamps") + } + bkey = string(sbkt.Get(bucketKeyName)) + local.Parent = string(sbkt.Get(bucketKeyParent)) + + return nil + }); err != nil { + return snapshot.Info{}, err + } + info, err := s.Snapshotter.Stat(ctx, bkey) if err != nil { return snapshot.Info{}, err } - info.Name = trimKey(info.Name) - if info.Parent != "" { - info.Parent = trimKey(info.Parent) + + return overlayInfo(info, local), nil +} + +func (s *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return snapshot.Info{}, err } - return info, nil + if info.Name == "" { + return snapshot.Info{}, errors.Wrap(errdefs.ErrInvalidArgument, "") + } + + var ( + bkey string + local = snapshot.Info{ + Name: info.Name, + } + ) + if err := update(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getSnapshotterBucket(tx, ns, s.name) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", info.Name) + } + sbkt := bkt.Bucket([]byte(info.Name)) + if sbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", info.Name) + } + + local.Labels, err = boltutil.ReadLabels(sbkt) + if err != nil { + return errors.Wrap(err, "failed to read labels") + } + if err := boltutil.ReadTimestamps(sbkt, &local.Created, &local.Updated); err != nil { + return errors.Wrap(err, "failed to read timestamps") + } + + // Handle field updates + if len(fieldpaths) > 0 { + for _, path := range fieldpaths { + if strings.HasPrefix(path, "labels.") { + if local.Labels == nil { + local.Labels = map[string]string{} + } + + key := strings.TrimPrefix(path, "labels.") + local.Labels[key] = info.Labels[key] + continue + } + + switch path { + case "labels": + local.Labels = info.Labels + default: + return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on snapshot %q", path, info.Name) + } + } + } else { + local.Labels = info.Labels + } + local.Updated = time.Now().UTC() + + if err := boltutil.WriteTimestamps(sbkt, local.Created, local.Updated); err != nil { + return errors.Wrap(err, "failed to read timestamps") + } + if err := boltutil.WriteLabels(sbkt, local.Labels); err != nil { + return errors.Wrap(err, "failed to read labels") + } + bkey = string(sbkt.Get(bucketKeyName)) + local.Parent = string(sbkt.Get(bucketKeyParent)) + + return nil + }); err != nil { + return snapshot.Info{}, err + } + + info, err = s.Snapshotter.Stat(ctx, bkey) + if err != nil { + return snapshot.Info{}, err + } + + return overlayInfo(info, local), nil +} + +func overlayInfo(info, overlay snapshot.Info) snapshot.Info { + // Merge info + info.Name = overlay.Name + info.Created = overlay.Created + info.Updated = overlay.Updated + info.Parent = overlay.Parent + if info.Labels == nil { + info.Labels = overlay.Labels + } else { + for k, v := range overlay.Labels { + overlay.Labels[k] = v + } + } + return info } func (s *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { @@ -106,20 +236,27 @@ func (s *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er return s.Snapshotter.Mounts(ctx, bkey) } -func (s *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return s.createSnapshot(ctx, key, parent, false) +func (s *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return s.createSnapshot(ctx, key, parent, false, opts) } -func (s *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return s.createSnapshot(ctx, key, parent, true) +func (s *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return s.createSnapshot(ctx, key, parent, true, opts) } -func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, readonly bool) ([]mount.Mount, error) { +func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, readonly bool, opts []snapshot.Opt) ([]mount.Mount, error) { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return nil, err } + var base snapshot.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return nil, err + } + } + var m []mount.Mount if err := update(ctx, s.db, func(tx *bolt.Tx) error { bkt, err := createSnapshotterBucket(tx, ns, s.name) @@ -127,24 +264,40 @@ func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, re return err } - bkey := string(bkt.Get([]byte(key))) - if bkey != "" { - return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v already exists", key) + bbkt, err := bkt.CreateBucket([]byte(key)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v already exists", key) + } + return err } var bparent string if parent != "" { - bparent = string(bkt.Get([]byte(parent))) - if bparent == "" { + pbkt := bkt.Bucket([]byte(parent)) + if pbkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", parent) } + bparent = string(pbkt.Get(bucketKeyName)) + + if err := bbkt.Put(bucketKeyParent, []byte(parent)); err != nil { + return err + } } sid, err := bkt.NextSequence() if err != nil { return err } - bkey = createKey(sid, ns, key) - if err := bkt.Put([]byte(key), []byte(bkey)); err != nil { + bkey := createKey(sid, ns, key) + if err := bbkt.Put(bucketKeyName, []byte(bkey)); err != nil { + return err + } + + ts := time.Now().UTC() + if err := boltutil.WriteTimestamps(bbkt, ts, ts); err != nil { + return err + } + if err := boltutil.WriteLabels(bbkt, base.Labels); err != nil { return err } @@ -162,37 +315,62 @@ func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, re return m, nil } -func (s *snapshotter) Commit(ctx context.Context, name, key string) error { +func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return err } + var base snapshot.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return err + } + } + return update(ctx, s.db, func(tx *bolt.Tx) error { bkt := getSnapshotterBucket(tx, ns, s.name) if bkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) } - nameKey := string(bkt.Get([]byte(name))) - if nameKey != "" { - return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v already exists", name) + bbkt, err := bkt.CreateBucket([]byte(name)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v already exists", name) + } + return err } - bkey := string(bkt.Get([]byte(key))) - if bkey == "" { + obkt := bkt.Bucket([]byte(key)) + if obkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) } + bkey := string(obkt.Get(bucketKeyName)) + parent := string(obkt.Get(bucketKeyParent)) + sid, err := bkt.NextSequence() if err != nil { return err } - nameKey = createKey(sid, ns, name) - if err := bkt.Put([]byte(name), []byte(nameKey)); err != nil { + + nameKey := createKey(sid, ns, name) + + if err := bbkt.Put(bucketKeyName, []byte(nameKey)); err != nil { return err } - if err := bkt.Delete([]byte(key)); err != nil { + if err := bbkt.Put(bucketKeyParent, []byte(parent)); err != nil { + return err + } + ts := time.Now().UTC() + if err := boltutil.WriteTimestamps(bbkt, ts, ts); err != nil { + return err + } + if err := boltutil.WriteLabels(bbkt, base.Labels); err != nil { + return err + } + if err := bkt.DeleteBucket([]byte(key)); err != nil { return err } @@ -210,16 +388,19 @@ func (s *snapshotter) Remove(ctx context.Context, key string) error { } return update(ctx, s.db, func(tx *bolt.Tx) error { + var bkey string bkt := getSnapshotterBucket(tx, ns, s.name) - if bkt == nil { - return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) + if bkt != nil { + sbkt := bkt.Bucket([]byte(key)) + if sbkt != nil { + bkey = string(sbkt.Get(bucketKeyName)) + } } - - bkey := string(bkt.Get([]byte(key))) if bkey == "" { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) } - if err := bkt.Delete([]byte(key)); err != nil { + + if err := bkt.DeleteBucket([]byte(key)); err != nil { return err } @@ -227,45 +408,93 @@ func (s *snapshotter) Remove(ctx context.Context, key string) error { }) } +type infoPair struct { + bkey string + info snapshot.Info +} + func (s *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshot.Info) error) error { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return err } - var keys []string + var ( + batchSize = 100 + pairs = []infoPair{} + lastKey string + ) - if err := view(ctx, s.db, func(tx *bolt.Tx) error { - bkt := getSnapshotterBucket(tx, ns, s.name) - if bkt == nil { - return nil - } - - bkt.ForEach(func(k, v []byte) error { - if len(v) > 0 { - keys = append(keys, string(v)) + for { + if err := view(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getSnapshotterBucket(tx, ns, s.name) + if bkt == nil { + return nil } + + c := bkt.Cursor() + + var k, v []byte + if lastKey == "" { + k, v = c.First() + } else { + k, v = c.Seek([]byte(lastKey)) + } + + for k != nil { + if v == nil { + if len(pairs) >= batchSize { + break + } + sbkt := bkt.Bucket(k) + + pair := infoPair{ + bkey: string(sbkt.Get(bucketKeyName)), + info: snapshot.Info{ + Name: string(k), + Parent: string(sbkt.Get(bucketKeyParent)), + }, + } + + err := boltutil.ReadTimestamps(sbkt, &pair.info.Created, &pair.info.Updated) + if err != nil { + return err + } + pair.info.Labels, err = boltutil.ReadLabels(sbkt) + if err != nil { + return err + } + + pairs = append(pairs, pair) + } + + k, v = c.Next() + } + + lastKey = string(k) + return nil - }) - - return nil - }); err != nil { - return err - } - - for _, k := range keys { - info, err := s.Snapshotter.Stat(ctx, k) - if err != nil { + }); err != nil { return err } - info.Name = trimKey(info.Name) - if info.Parent != "" { - info.Parent = trimKey(info.Parent) + for _, pair := range pairs { + info, err := s.Snapshotter.Stat(ctx, pair.bkey) + if err != nil { + return err + } + + if err := fn(ctx, overlayInfo(info, pair.info)); err != nil { + return err + } } - if err := fn(ctx, info); err != nil { - return err + + if lastKey == "" { + break } + + pairs = pairs[:0] + } return nil diff --git a/services/snapshot/client.go b/services/snapshot/client.go index c5b4ab53b..a9b9ffe67 100644 --- a/services/snapshot/client.go +++ b/services/snapshot/client.go @@ -9,6 +9,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/snapshot" + protobuftypes "github.com/gogo/protobuf/types" ) // NewSnapshotterFromClient returns a new Snapshotter which communicates @@ -37,6 +38,21 @@ func (r *remoteSnapshotter) Stat(ctx context.Context, key string) (snapshot.Info return toInfo(resp.Info), nil } +func (r *remoteSnapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + resp, err := r.client.Update(ctx, + &snapshotapi.UpdateSnapshotRequest{ + Snapshotter: r.snapshotterName, + Info: fromInfo(info), + UpdateMask: &protobuftypes.FieldMask{ + Paths: fieldpaths, + }, + }) + if err != nil { + return snapshot.Info{}, errdefs.FromGRPC(err) + } + return toInfo(resp.Info), nil +} + func (r *remoteSnapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { resp, err := r.client.Usage(ctx, &snapshotapi.UsageRequest{ Snapshotter: r.snapshotterName, @@ -59,11 +75,18 @@ func (r *remoteSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mou return toMounts(resp.Mounts), nil } -func (r *remoteSnapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { +func (r *remoteSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + var local snapshot.Info + for _, opt := range opts { + if err := opt(&local); err != nil { + return nil, err + } + } resp, err := r.client.Prepare(ctx, &snapshotapi.PrepareSnapshotRequest{ Snapshotter: r.snapshotterName, Key: key, Parent: parent, + Labels: local.Labels, }) if err != nil { return nil, errdefs.FromGRPC(err) @@ -71,11 +94,18 @@ func (r *remoteSnapshotter) Prepare(ctx context.Context, key, parent string) ([] return toMounts(resp.Mounts), nil } -func (r *remoteSnapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { +func (r *remoteSnapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + var local snapshot.Info + for _, opt := range opts { + if err := opt(&local); err != nil { + return nil, err + } + } resp, err := r.client.View(ctx, &snapshotapi.ViewSnapshotRequest{ Snapshotter: r.snapshotterName, Key: key, Parent: parent, + Labels: local.Labels, }) if err != nil { return nil, errdefs.FromGRPC(err) @@ -83,11 +113,18 @@ func (r *remoteSnapshotter) View(ctx context.Context, key, parent string) ([]mou return toMounts(resp.Mounts), nil } -func (r *remoteSnapshotter) Commit(ctx context.Context, name, key string) error { +func (r *remoteSnapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { + var local snapshot.Info + for _, opt := range opts { + if err := opt(&local); err != nil { + return err + } + } _, err := r.client.Commit(ctx, &snapshotapi.CommitSnapshotRequest{ Snapshotter: r.snapshotterName, Name: name, Key: key, + Labels: local.Labels, }) return errdefs.FromGRPC(err) } @@ -130,14 +167,20 @@ func toKind(kind snapshotapi.Kind) snapshot.Kind { if kind == snapshotapi.KindActive { return snapshot.KindActive } + if kind == snapshotapi.KindView { + return snapshot.KindView + } return snapshot.KindCommitted } func toInfo(info snapshotapi.Info) snapshot.Info { return snapshot.Info{ - Name: info.Name, - Parent: info.Parent, - Kind: toKind(info.Kind), + Name: info.Name, + Parent: info.Parent, + Kind: toKind(info.Kind), + Created: info.CreatedAt, + Updated: info.UpdatedAt, + Labels: info.Labels, } } diff --git a/services/snapshot/service.go b/services/snapshot/service.go index 8b105e8a2..6c6ef8818 100644 --- a/services/snapshot/service.go +++ b/services/snapshot/service.go @@ -97,9 +97,12 @@ func (s *service) Prepare(ctx context.Context, pr *snapshotapi.PrepareSnapshotRe if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store - mounts, err := sn.Prepare(ctx, pr.Key, pr.Parent) + + var opts []snapshot.Opt + if pr.Labels != nil { + opts = append(opts, snapshot.WithLabels(pr.Labels)) + } + mounts, err := sn.Prepare(ctx, pr.Key, pr.Parent, opts...) if err != nil { return nil, errdefs.ToGRPC(err) } @@ -121,9 +124,11 @@ func (s *service) View(ctx context.Context, pr *snapshotapi.ViewSnapshotRequest) if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store - mounts, err := sn.View(ctx, pr.Key, pr.Parent) + var opts []snapshot.Opt + if pr.Labels != nil { + opts = append(opts, snapshot.WithLabels(pr.Labels)) + } + mounts, err := sn.View(ctx, pr.Key, pr.Parent, opts...) if err != nil { return nil, errdefs.ToGRPC(err) } @@ -138,8 +143,7 @@ func (s *service) Mounts(ctx context.Context, mr *snapshotapi.MountsRequest) (*s if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store + mounts, err := sn.Mounts(ctx, mr.Key) if err != nil { return nil, errdefs.ToGRPC(err) @@ -155,9 +159,12 @@ func (s *service) Commit(ctx context.Context, cr *snapshotapi.CommitSnapshotRequ if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store - if err := sn.Commit(ctx, cr.Name, cr.Key); err != nil { + + var opts []snapshot.Opt + if cr.Labels != nil { + opts = append(opts, snapshot.WithLabels(cr.Labels)) + } + if err := sn.Commit(ctx, cr.Name, cr.Key, opts...); err != nil { return nil, errdefs.ToGRPC(err) } @@ -176,8 +183,7 @@ func (s *service) Remove(ctx context.Context, rr *snapshotapi.RemoveSnapshotRequ if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store + if err := sn.Remove(ctx, rr.Key); err != nil { return nil, errdefs.ToGRPC(err) } @@ -196,7 +202,7 @@ func (s *service) Stat(ctx context.Context, sr *snapshotapi.StatSnapshotRequest) if err != nil { return nil, err } - // TODO: Apply namespace + info, err := sn.Stat(ctx, sr.Key) if err != nil { return nil, errdefs.ToGRPC(err) @@ -205,12 +211,27 @@ func (s *service) Stat(ctx context.Context, sr *snapshotapi.StatSnapshotRequest) return &snapshotapi.StatSnapshotResponse{Info: fromInfo(info)}, nil } +func (s *service) Update(ctx context.Context, sr *snapshotapi.UpdateSnapshotRequest) (*snapshotapi.UpdateSnapshotResponse, error) { + log.G(ctx).WithField("key", sr.Info.Name).Debugf("Updating snapshot") + sn, err := s.getSnapshotter(sr.Snapshotter) + if err != nil { + return nil, err + } + + info, err := sn.Update(ctx, toInfo(sr.Info), sr.UpdateMask.GetPaths()...) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + + return &snapshotapi.UpdateSnapshotResponse{Info: fromInfo(info)}, nil +} + func (s *service) List(sr *snapshotapi.ListSnapshotsRequest, ss snapshotapi.Snapshots_ListServer) error { sn, err := s.getSnapshotter(sr.Snapshotter) if err != nil { return err } - // TODO: Apply namespace + var ( buffer []snapshotapi.Info sendBlock = func(block []snapshotapi.Info) error { @@ -250,7 +271,7 @@ func (s *service) Usage(ctx context.Context, ur *snapshotapi.UsageRequest) (*sna if err != nil { return nil, err } - // TODO: Apply namespace + usage, err := sn.Usage(ctx, ur.Key) if err != nil { return nil, errdefs.ToGRPC(err) @@ -263,14 +284,20 @@ func fromKind(kind snapshot.Kind) snapshotapi.Kind { if kind == snapshot.KindActive { return snapshotapi.KindActive } + if kind == snapshot.KindView { + return snapshotapi.KindView + } return snapshotapi.KindCommitted } func fromInfo(info snapshot.Info) snapshotapi.Info { return snapshotapi.Info{ - Name: info.Name, - Parent: info.Parent, - Kind: fromKind(info.Kind), + Name: info.Name, + Parent: info.Parent, + Kind: fromKind(info.Kind), + CreatedAt: info.Created, + UpdatedAt: info.Updated, + Labels: info.Labels, } } diff --git a/snapshot/btrfs/btrfs.go b/snapshot/btrfs/btrfs.go index 44ae8bd46..864c039b6 100644 --- a/snapshot/btrfs/btrfs.go +++ b/snapshot/btrfs/btrfs.go @@ -103,6 +103,25 @@ func (b *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + // Usage retrieves the disk usage of the top-level snapshot. func (b *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { panic("not implemented") @@ -129,15 +148,15 @@ func (b *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (b *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return b.makeSnapshot(ctx, snapshot.KindActive, key, parent) +func (b *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return b.makeSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (b *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return b.makeSnapshot(ctx, snapshot.KindView, key, parent) +func (b *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return b.makeSnapshot(ctx, snapshot.KindView, key, parent, opts) } -func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { ctx, t, err := b.ms.TransactionContext(ctx, true) if err != nil { return nil, err @@ -150,7 +169,7 @@ func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, } }() - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { return nil, err } @@ -214,7 +233,7 @@ func (b *snapshotter) mounts(dir string) ([]mount.Mount, error) { }, nil } -func (b *snapshotter) Commit(ctx context.Context, name, key string) (err error) { +func (b *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) (err error) { ctx, t, err := b.ms.TransactionContext(ctx, true) if err != nil { return err @@ -227,7 +246,7 @@ func (b *snapshotter) Commit(ctx context.Context, name, key string) (err error) } }() - id, err := storage.CommitActive(ctx, key, name, snapshot.Usage{}) // TODO(stevvooe): Resolve a usage value for btrfs + id, err := storage.CommitActive(ctx, key, name, snapshot.Usage{}, opts...) // TODO(stevvooe): Resolve a usage value for btrfs if err != nil { return errors.Wrap(err, "failed to commit") } diff --git a/snapshot/naive/naive.go b/snapshot/naive/naive.go index a78a76145..f2f849cc1 100644 --- a/snapshot/naive/naive.go +++ b/snapshot/naive/naive.go @@ -70,6 +70,25 @@ func (o *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { ctx, t, err := o.ms.TransactionContext(ctx, false) if err != nil { @@ -93,12 +112,12 @@ func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, er return usage, nil } -func (o *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindActive, key, parent) +func (o *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (o *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindView, key, parent) +func (o *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindView, key, parent, opts) } // Mounts returns the mounts for the transaction identified by key. Can be @@ -118,7 +137,7 @@ func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er return o.mounts(s), nil } -func (o *snapshotter) Commit(ctx context.Context, name, key string) error { +func (o *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return err @@ -134,7 +153,7 @@ func (o *snapshotter) Commit(ctx context.Context, name, key string) error { return err } - if _, err := storage.CommitActive(ctx, key, name, snapshot.Usage(usage)); err != nil { + if _, err := storage.CommitActive(ctx, key, name, snapshot.Usage(usage), opts...); err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") } @@ -203,7 +222,7 @@ func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { var ( err error path, td string @@ -235,7 +254,7 @@ func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, ke return nil, err } - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") diff --git a/snapshot/overlay/overlay.go b/snapshot/overlay/overlay.go index 7d1616bc6..35644b07a 100644 --- a/snapshot/overlay/overlay.go +++ b/snapshot/overlay/overlay.go @@ -89,6 +89,25 @@ func (o *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + // Usage returns the resources taken by the snapshot identified by key. // // For active snapshots, this will scan the usage of the overlay "diff" (aka @@ -121,12 +140,12 @@ func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, er return usage, nil } -func (o *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindActive, key, parent) +func (o *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (o *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindView, key, parent) +func (o *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindView, key, parent, opts) } // Mounts returns the mounts for the transaction identified by key. Can be @@ -146,7 +165,7 @@ func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er return o.mounts(s), nil } -func (o *snapshotter) Commit(ctx context.Context, name, key string) error { +func (o *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return err @@ -171,7 +190,7 @@ func (o *snapshotter) Commit(ctx context.Context, name, key string) error { return err } - if _, err = storage.CommitActive(ctx, key, name, snapshot.Usage(usage)); err != nil { + if _, err = storage.CommitActive(ctx, key, name, snapshot.Usage(usage), opts...); err != nil { return errors.Wrap(err, "failed to commit snapshot") } return t.Commit() @@ -230,7 +249,7 @@ func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { var ( path string snapshotDir = filepath.Join(o.root, "snapshots") @@ -270,7 +289,7 @@ func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, ke return nil, err } - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") diff --git a/snapshot/snapshotter.go b/snapshot/snapshotter.go index c2cd73fc8..35d645000 100644 --- a/snapshot/snapshotter.go +++ b/snapshot/snapshotter.go @@ -2,12 +2,13 @@ package snapshot import ( "context" + "time" "github.com/containerd/containerd/mount" ) // Kind identifies the kind of snapshot. -type Kind int +type Kind uint8 // definitions of snapshot kinds const ( @@ -31,9 +32,12 @@ func (k Kind) String() string { // Info provides information about a particular snapshot. type Info struct { - Kind Kind // active or committed snapshot - Name string // name or key of snapshot - Parent string // name of parent snapshot + Kind Kind // active or committed snapshot + Name string // name or key of snapshot + Parent string // name of parent snapshot + Labels map[string]string // Labels for snapshot + Created time.Time // Created time + Updated time.Time // Last update time } // Usage defines statistics for disk resources consumed by the snapshot. @@ -177,6 +181,11 @@ type Snapshotter interface { // the kind of snapshot. Stat(ctx context.Context, key string) (Info, error) + // Update updates the infor for a snapshot. + // + // Only mutable properties of a snapshot may be updated. + Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error) + // Usage returns the resource usage of an active or committed snapshot // excluding the usage of parent snapshots. // @@ -208,7 +217,7 @@ type Snapshotter interface { // one is done with the transaction, Remove should be called on the key. // // Multiple calls to Prepare or View with the same key should fail. - Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) + Prepare(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error) // View behaves identically to Prepare except the result may not be // committed back to the snapshot snapshotter. View returns a readonly view on @@ -223,7 +232,7 @@ type Snapshotter interface { // Commit may not be called on the provided key and will return an error. // To collect the resources associated with key, Remove must be called with // key as the argument. - View(ctx context.Context, key, parent string) ([]mount.Mount, error) + View(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error) // Commit captures the changes between key and its parent into a snapshot // identified by name. The name can then be used with the snapshotter's other @@ -235,7 +244,7 @@ type Snapshotter interface { // Commit may be called multiple times on the same key. Snapshots created // in this manner will all reference the parent used to start the // transaction. - Commit(ctx context.Context, name, key string) error + Commit(ctx context.Context, name, key string, opts ...Opt) error // Remove the committed or active snapshot by the provided key. // @@ -249,3 +258,14 @@ type Snapshotter interface { // snapshotter, the function will be called. Walk(ctx context.Context, fn func(context.Context, Info) error) error } + +// Opt allows setting mutable snapshot properties on creation +type Opt func(info *Info) error + +// WithLabels adds labels to a created snapshot +func WithLabels(labels map[string]string) Opt { + return func(info *Info) error { + info.Labels = labels + return nil + } +} diff --git a/snapshot/storage/bolt.go b/snapshot/storage/bolt.go index abe997c29..4f0c677ce 100644 --- a/snapshot/storage/bolt.go +++ b/snapshot/storage/bolt.go @@ -4,12 +4,13 @@ import ( "context" "encoding/binary" "fmt" + "strings" + "time" "github.com/boltdb/bolt" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/snapshot" - db "github.com/containerd/containerd/snapshot/storage/proto" - "github.com/gogo/protobuf/proto" "github.com/pkg/errors" ) @@ -18,6 +19,12 @@ var ( bucketKeySnapshot = []byte("snapshots") bucketKeyParents = []byte("parents") + bucketKeyID = []byte("id") + bucketKeyParent = []byte("parent") + bucketKeyKind = []byte("kind") + bucketKeyInodes = []byte("inodes") + bucketKeySize = []byte("size") + // ErrNoTransaction is returned when an operation is attempted with // a context which is not inside of a transaction. ErrNoTransaction = errors.New("no transaction in context") @@ -65,24 +72,75 @@ func getParentPrefix(b []byte) uint64 { // GetInfo returns the snapshot Info directly from the metadata. Requires a // context with a storage transaction. func GetInfo(ctx context.Context, key string) (string, snapshot.Info, snapshot.Usage, error) { - var ss db.Snapshot - err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - return getSnapshot(bkt, key, &ss) + var ( + id uint64 + su snapshot.Usage + si = snapshot.Info{ + Name: key, + } + ) + err := withSnapshotBucket(ctx, key, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + getUsage(bkt, &su) + return readSnapshot(bkt, &id, &si) }) if err != nil { return "", snapshot.Info{}, snapshot.Usage{}, err } - usage := snapshot.Usage{ - Inodes: ss.Inodes, - Size: ss.Size_, - } + return fmt.Sprintf("%d", id), si, su, nil +} - return fmt.Sprint(ss.ID), snapshot.Info{ - Name: key, - Parent: ss.Parent, - Kind: snapshot.Kind(ss.Kind), - }, usage, nil +func UpdateInfo(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + updated := snapshot.Info{ + Name: info.Name, + } + err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + sbkt := bkt.Bucket([]byte(info.Name)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") + } + if err := readSnapshot(sbkt, nil, &updated); err != nil { + return err + } + + if len(fieldpaths) > 0 { + for _, path := range fieldpaths { + if strings.HasPrefix(path, "labels.") { + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + + key := strings.TrimPrefix(path, "labels.") + updated.Labels[key] = info.Labels[key] + continue + } + + switch path { + case "labels": + updated.Labels = info.Labels + default: + return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on snapshot %q", path, info.Name) + } + } + } else { + // Set mutable fields + updated.Labels = info.Labels + } + updated.Updated = time.Now().UTC() + if err := boltutil.WriteTimestamps(sbkt, updated.Created, updated.Updated); err != nil { + return err + } + + if err := boltutil.WriteLabels(sbkt, updated.Labels); err != nil { + return err + } + + return nil + }) + if err != nil { + return snapshot.Info{}, err + } + return updated, nil } // WalkInfo iterates through all metadata Info for the stored snapshots and @@ -91,21 +149,21 @@ func GetInfo(ctx context.Context, key string) (string, snapshot.Info, snapshot.U func WalkInfo(ctx context.Context, fn func(context.Context, snapshot.Info) error) error { return withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { return bkt.ForEach(func(k, v []byte) error { - // skip nested buckets - if v == nil { + // skip non buckets + if v != nil { return nil } - var ss db.Snapshot - if err := proto.Unmarshal(v, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + var ( + sbkt = bkt.Bucket(k) + si = snapshot.Info{ + Name: string(k), + } + ) + if err := readSnapshot(sbkt, nil, &si); err != nil { + return err } - info := snapshot.Info{ - Name: string(k), - Parent: ss.Parent, - Kind: snapshot.Kind(ss.Kind), - } - return fn(ctx, info) + return fn(ctx, si) }) }) } @@ -114,30 +172,25 @@ func WalkInfo(ctx context.Context, fn func(context.Context, snapshot.Info) error // referenced by the given key. Requires a context with a storage transaction. func GetSnapshot(ctx context.Context, key string) (s Snapshot, err error) { err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - b := bkt.Get([]byte(key)) - if len(b) == 0 { - return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") } - var ss db.Snapshot - if err := proto.Unmarshal(b, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") - } + s.ID = fmt.Sprintf("%d", readID(sbkt)) + s.Kind = readKind(sbkt) - if ss.Kind != db.KindActive && ss.Kind != db.KindView { + if s.Kind != snapshot.KindActive && s.Kind != snapshot.KindView { return errors.Wrapf(errdefs.ErrFailedPrecondition, "requested snapshot %v not active or view", key) } - s.ID = fmt.Sprintf("%d", ss.ID) - s.Kind = snapshot.Kind(ss.Kind) - - if ss.Parent != "" { - var parent db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &parent); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if parentKey := sbkt.Get(bucketKeyParent); len(parentKey) > 0 { + spbkt := bkt.Bucket(parentKey) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "parent does not exist") } - s.ParentIDs, err = parents(bkt, &parent) + s.ParentIDs, err = parents(bkt, spbkt, readID(spbkt)) if err != nil { return errors.Wrap(err, "failed to get parent chain") } @@ -152,30 +205,39 @@ func GetSnapshot(ctx context.Context, key string) (s Snapshot, err error) { } // CreateSnapshot inserts a record for an active or view snapshot with the provided parent. -func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) (s Snapshot, err error) { +func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts ...snapshot.Opt) (s Snapshot, err error) { switch kind { case snapshot.KindActive, snapshot.KindView: default: return Snapshot{}, errors.Wrapf(errdefs.ErrInvalidArgument, "snapshot type %v invalid; only snapshots of type Active or View can be created", kind) } + var base snapshot.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return Snapshot{}, err + } + } err = createBucketIfNotExists(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { var ( - parentS *db.Snapshot + spbkt *bolt.Bucket ) if parent != "" { - parentS = new(db.Snapshot) - if err := getSnapshot(bkt, parent, parentS); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + spbkt = bkt.Bucket([]byte(parent)) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "missing parent bucket") } - if parentS.Kind != db.KindCommitted { + if readKind(spbkt) != snapshot.KindCommitted { return errors.Wrap(errdefs.ErrInvalidArgument, "parent is not committed snapshot") } } - b := bkt.Get([]byte(key)) - if len(b) != 0 { - return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v", key) + sbkt, err := bkt.CreateBucket([]byte(key)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v", key) + } + return err } id, err := bkt.NextSequence() @@ -183,23 +245,28 @@ func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) return errors.Wrap(err, "unable to get identifier") } - ss := db.Snapshot{ - ID: id, - Parent: parent, - Kind: db.Kind(kind), + t := time.Now().UTC() + si := snapshot.Info{ + Parent: parent, + Kind: kind, + Labels: base.Labels, + Created: t, + Updated: t, } - if err := putSnapshot(bkt, key, &ss); err != nil { + if err := putSnapshot(sbkt, id, si); err != nil { return err } - if parentS != nil { + if spbkt != nil { + pid := readID(spbkt) + // Store a backlink from the key to the parent. Store the snapshot name // as the value to allow following the backlink to the snapshot value. - if err := pbkt.Put(parentKey(parentS.ID, ss.ID), []byte(key)); err != nil { + if err := pbkt.Put(parentKey(pid, id), []byte(key)); err != nil { return errors.Wrap(err, "failed to write parent link") } - s.ParentIDs, err = parents(bkt, parentS) + s.ParentIDs, err = parents(bkt, spbkt, pid) if err != nil { return errors.Wrap(err, "failed to get parent chain") } @@ -219,47 +286,50 @@ func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) // Remove removes a snapshot from the metastore. The string identifier for the // snapshot is returned as well as the kind. The provided context must contain a // writable transaction. -func Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err error) { - err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - var ss db.Snapshot - b := bkt.Get([]byte(key)) - if len(b) == 0 { +func Remove(ctx context.Context, key string) (string, snapshot.Kind, error) { + var ( + id uint64 + si snapshot.Info + ) + + if err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) } - if err := proto.Unmarshal(b, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + if err := readSnapshot(sbkt, &id, &si); err != nil { + errors.Wrapf(err, "failed to read snapshot %s", key) } if pbkt != nil { - k, _ := pbkt.Cursor().Seek(parentPrefixKey(ss.ID)) - if getParentPrefix(k) == ss.ID { + k, _ := pbkt.Cursor().Seek(parentPrefixKey(id)) + if getParentPrefix(k) == id { return errors.Errorf("cannot remove snapshot with child") } - if ss.Parent != "" { - var ps db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &ps); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if si.Parent != "" { + spbkt := bkt.Bucket([]byte(si.Parent)) + if spbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) } - if err := pbkt.Delete(parentKey(ps.ID, ss.ID)); err != nil { - return errors.Wrap(err, "failed to delte parent link") + if err := pbkt.Delete(parentKey(readID(spbkt), id)); err != nil { + return errors.Wrap(err, "failed to delete parent link") } } } - if err := bkt.Delete([]byte(key)); err != nil { + if err := bkt.DeleteBucket([]byte(key)); err != nil { return errors.Wrap(err, "failed to delete snapshot") } - id = fmt.Sprintf("%d", ss.ID) - k = snapshot.Kind(ss.Kind) - return nil - }) + }); err != nil { + return "", 0, err + } - return + return fmt.Sprintf("%d", id), si.Kind, nil } // CommitActive renames the active snapshot transaction referenced by `key` @@ -268,52 +338,94 @@ func Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err er // lookup or removal. The returned string identifier for the committed snapshot // is the same identifier of the original active snapshot. The provided context // must contain a writable transaction. -func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage) (id string, err error) { - err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - b := bkt.Get([]byte(name)) - if len(b) != 0 { - return errors.Wrapf(errdefs.ErrAlreadyExists, "committed snapshot %v", name) +func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage, opts ...snapshot.Opt) (string, error) { + var ( + id uint64 + base snapshot.Info + ) + for _, opt := range opts { + if err := opt(&base); err != nil { + return "", err + } + } + + if err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + dbkt, err := bkt.CreateBucket([]byte(name)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errdefs.ErrAlreadyExists + } + return errors.Wrapf(err, "committed snapshot %v", name) + } + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "failed to get active snapshot") } - var ss db.Snapshot - if err := getSnapshot(bkt, key, &ss); err != nil { - return errors.Wrap(err, "failed to get active snapshot") + var si snapshot.Info + if err := readSnapshot(sbkt, &id, &si); err != nil { + return errors.Wrap(err, "failed to read snapshot") } - if ss.Kind != db.KindActive { + + if si.Kind != snapshot.KindActive { return errors.Wrapf(errdefs.ErrFailedPrecondition, "snapshot %v is not active", name) } + si.Kind = snapshot.KindCommitted + si.Created = time.Now().UTC() + si.Updated = si.Created - ss.Kind = db.KindCommitted - ss.Inodes = usage.Inodes - ss.Size_ = usage.Size + // Replace labels, do not inherit + si.Labels = base.Labels - if err := putSnapshot(bkt, name, &ss); err != nil { + if err := putSnapshot(dbkt, id, si); err != nil { return err } - if err := bkt.Delete([]byte(key)); err != nil { + if err := putUsage(dbkt, usage); err != nil { + return err + } + if err := bkt.DeleteBucket([]byte(key)); err != nil { return errors.Wrap(err, "failed to delete active") } - if ss.Parent != "" { - var ps db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &ps); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if si.Parent != "" { + spbkt := bkt.Bucket([]byte(si.Parent)) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "missing parent") } + pid := readID(spbkt) // Updates parent back link to use new key - if err := pbkt.Put(parentKey(ps.ID, ss.ID), []byte(name)); err != nil { + if err := pbkt.Put(parentKey(pid, id), []byte(name)); err != nil { return errors.Wrap(err, "failed to update parent link") } } - id = fmt.Sprintf("%d", ss.ID) - return nil - }) - if err != nil { + }); err != nil { return "", err } - return + return fmt.Sprintf("%d", id), nil +} + +func withSnapshotBucket(ctx context.Context, key string, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error { + t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor) + if !ok { + return ErrNoTransaction + } + bkt := t.tx.Bucket(bucketKeyStorageVersion) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "bucket does not exist") + } + bkt = bkt.Bucket(bucketKeySnapshot) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshots bucket does not exist") + } + bkt = bkt.Bucket([]byte(key)) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") + } + + return fn(ctx, bkt, bkt.Bucket(bucketKeyParents)) } func withBucket(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error { @@ -349,41 +461,133 @@ func createBucketIfNotExists(ctx context.Context, fn func(context.Context, *bolt return fn(ctx, sbkt, pbkt) } -func parents(bkt *bolt.Bucket, parent *db.Snapshot) (parents []string, err error) { +func parents(bkt, pbkt *bolt.Bucket, parent uint64) (parents []string, err error) { for { - parents = append(parents, fmt.Sprintf("%d", parent.ID)) + parents = append(parents, fmt.Sprintf("%d", parent)) - if parent.Parent == "" { + parentKey := pbkt.Get(bucketKeyParent) + if len(parentKey) == 0 { return } - - var ps db.Snapshot - if err := getSnapshot(bkt, parent.Parent, &ps); err != nil { - return nil, errors.Wrap(err, "failed to get parent snapshot") + pbkt = bkt.Bucket(parentKey) + if pbkt == nil { + return nil, errors.Wrap(errdefs.ErrNotFound, "missing parent") } - parent = &ps + + parent = readID(pbkt) } } -func getSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error { - b := bkt.Get([]byte(key)) - if len(b) == 0 { - return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) +func readKind(bkt *bolt.Bucket) (k snapshot.Kind) { + kind := bkt.Get(bucketKeyKind) + if len(kind) == 1 { + k = snapshot.Kind(kind[0]) } - if err := proto.Unmarshal(b, ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + return +} + +func readID(bkt *bolt.Bucket) uint64 { + id, _ := binary.Uvarint(bkt.Get(bucketKeyID)) + return id +} + +func readSnapshot(bkt *bolt.Bucket, id *uint64, si *snapshot.Info) error { + if id != nil { + *id = readID(bkt) } + if si != nil { + si.Kind = readKind(bkt) + si.Parent = string(bkt.Get(bucketKeyParent)) + + if err := boltutil.ReadTimestamps(bkt, &si.Created, &si.Updated); err != nil { + return err + } + + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err + } + si.Labels = labels + } + return nil } -func putSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error { - b, err := proto.Marshal(ss) +func putSnapshot(bkt *bolt.Bucket, id uint64, si snapshot.Info) error { + idEncoded, err := encodeID(id) if err != nil { - return errors.Wrap(err, "failed to marshal snapshot") + return err } - if err := bkt.Put([]byte(key), b); err != nil { - return errors.Wrap(err, "failed to save snapshot") + updates := [][2][]byte{ + {bucketKeyID, idEncoded}, + {bucketKeyKind, []byte{byte(si.Kind)}}, + } + if si.Parent != "" { + updates = append(updates, [2][]byte{bucketKeyParent, []byte(si.Parent)}) + } + for _, v := range updates { + if err := bkt.Put(v[0], v[1]); err != nil { + return err + } + } + if err := boltutil.WriteTimestamps(bkt, si.Created, si.Updated); err != nil { + return err + } + + if err := boltutil.WriteLabels(bkt, si.Labels); err != nil { + return err + } + + return nil +} + +func getUsage(bkt *bolt.Bucket, usage *snapshot.Usage) { + usage.Inodes, _ = binary.Varint(bkt.Get(bucketKeyInodes)) + usage.Size, _ = binary.Varint(bkt.Get(bucketKeySize)) +} + +func putUsage(bkt *bolt.Bucket, usage snapshot.Usage) error { + for _, v := range []struct { + key []byte + value int64 + }{ + {bucketKeyInodes, usage.Inodes}, + {bucketKeySize, usage.Size}, + } { + e, err := encodeSize(v.value) + if err != nil { + return err + } + if err := bkt.Put(v.key, e); err != nil { + return err + } } return nil } + +func encodeSize(size int64) ([]byte, error) { + var ( + buf [binary.MaxVarintLen64]byte + sizeEncoded []byte = buf[:] + ) + sizeEncoded = sizeEncoded[:binary.PutVarint(sizeEncoded, size)] + + if len(sizeEncoded) == 0 { + return nil, fmt.Errorf("failed encoding size = %v", size) + } + return sizeEncoded, nil +} + +func encodeID(id uint64) ([]byte, error) { + var ( + buf [binary.MaxVarintLen64]byte + idEncoded []byte = buf[:] + ) + idEncoded = idEncoded[:binary.PutUvarint(idEncoded, id)] + + if len(idEncoded) == 0 { + return nil, fmt.Errorf("failed encoding id = %v", id) + } + return idEncoded, nil +} diff --git a/snapshot/storage/bolt_test.go b/snapshot/storage/bolt_test.go index cacbab270..a3e73a6d5 100644 --- a/snapshot/storage/bolt_test.go +++ b/snapshot/storage/bolt_test.go @@ -5,8 +5,7 @@ import ( "testing" // Does not require root but flag must be defined for snapshot tests - "github.com/containerd/containerd/snapshot" - "github.com/containerd/containerd/snapshot/storage/proto" + _ "github.com/containerd/containerd/testutil" ) @@ -16,34 +15,6 @@ func TestMetastore(t *testing.T) { }) } -// TestKidnConversion ensures we can blindly cast from protobuf types. -func TestKindConversion(t *testing.T) { - for _, testcase := range []struct { - s snapshot.Kind - p proto.Kind - }{ - { - s: snapshot.KindView, - p: proto.KindView, - }, - { - s: snapshot.KindActive, - p: proto.KindActive, - }, - { - s: snapshot.KindCommitted, - p: proto.KindCommitted, - }, - } { - if testcase.s != snapshot.Kind(testcase.p) { - t.Fatalf("snapshot kind value cast failed: %v != %v", testcase.s, testcase.p) - } - if testcase.p != proto.Kind(testcase.s) { - t.Fatalf("proto kind value cast failed: %v != %v", testcase.s, testcase.p) - } - } -} - func BenchmarkSuite(b *testing.B) { Benchmarks(b, "BoltDBBench", func(root string) (*MetaStore, error) { return NewMetaStore(filepath.Join(root, "metadata.db")) diff --git a/snapshot/storage/metastore_test.go b/snapshot/storage/metastore_test.go index 9aa164f66..91455a295 100644 --- a/snapshot/storage/metastore_test.go +++ b/snapshot/storage/metastore_test.go @@ -2,9 +2,11 @@ package storage import ( "context" + "fmt" "io/ioutil" "os" "testing" + "time" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/snapshot" @@ -40,6 +42,7 @@ func MetaStoreSuite(t *testing.T, name string, meta func(root string) (*MetaStor t.Run("Remove", makeTest(t, name, meta, inWriteTransaction(testRemove))) t.Run("RemoveNotExist", makeTest(t, name, meta, inWriteTransaction(testRemoveNotExist))) t.Run("RemoveWithChildren", makeTest(t, name, meta, inWriteTransaction(testRemoveWithChildren))) + t.Run("ParentIDs", makeTest(t, name, meta, inWriteTransaction(testParents))) } // makeTest creates a testsuite with a writable transaction @@ -236,6 +239,9 @@ func testGetInfo(ctx context.Context, t *testing.T, ms *MetaStore) { if err != nil { t.Fatalf("GetInfo on %v failed: %+v", key, err) } + // TODO: Check timestamp range + info.Created = time.Time{} + info.Updated = time.Time{} assert.Equal(t, expected, info) } } @@ -251,6 +257,9 @@ func testWalk(ctx context.Context, t *testing.T, ms *MetaStore) { if _, ok := found[info.Name]; ok { return errors.Errorf("entry already encountered") } + // TODO: Check time range + info.Created = time.Time{} + info.Updated = time.Time{} found[info.Name] = info return nil }) @@ -545,3 +554,86 @@ func testRemoveNotExist(ctx context.Context, t *testing.T, ms *MetaStore) { _, _, err := Remove(ctx, "does-not-exist") assertNotExist(t, err) } + +func testParents(ctx context.Context, t *testing.T, ms *MetaStore) { + if err := basePopulate(ctx, ms); err != nil { + t.Fatalf("Populate failed: %+v", err) + } + + testcases := []struct { + Name string + Parents int + }{ + {"committed-1", 0}, + {"committed-2", 1}, + {"active-1", 0}, + {"active-2", 1}, + {"active-3", 2}, + {"view-1", 0}, + {"view-2", 2}, + } + + for _, tc := range testcases { + name := tc.Name + expectedID := "" + expectedParents := []string{} + for i := tc.Parents; i >= 0; i-- { + sid, info, _, err := GetInfo(ctx, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + var ( + id string + parents []string + ) + if info.Kind == snapshot.KindCommitted { + // When commited, create view and resolve from view + nid := fmt.Sprintf("test-%s-%d", tc.Name, i) + s, err := CreateSnapshot(ctx, snapshot.KindView, nid, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + if len(s.ParentIDs) != i+1 { + t.Fatalf("Unexpected number of parents for view of %s: %d, expected %d", name, len(s.ParentIDs), i+1) + } + id = s.ParentIDs[0] + parents = s.ParentIDs[1:] + } else { + s, err := GetSnapshot(ctx, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + if len(s.ParentIDs) != i { + t.Fatalf("Unexpected number of parents for %s: %d, expected %d", name, len(s.ParentIDs), i) + } + + id = s.ID + parents = s.ParentIDs + } + if sid != id { + t.Fatalf("Info ID mismatched resolved snapshot ID for %s, %s vs %s", name, sid, id) + } + + if expectedID != "" { + if id != expectedID { + t.Errorf("Unexpected ID of parent: %s, expected %s", id, expectedID) + } + } + + if len(expectedParents) > 0 { + for j := range expectedParents { + if parents[j] != expectedParents[j] { + t.Errorf("Unexpected ID in parent array at %d: %s, expected %s", j, parents[j], expectedParents[j]) + } + } + } + + if i > 0 { + name = info.Parent + expectedID = parents[0] + expectedParents = parents[1:] + } + + } + } +} diff --git a/snapshot/storage/proto/record.pb.go b/snapshot/storage/proto/record.pb.go deleted file mode 100644 index bfaa67d0b..000000000 --- a/snapshot/storage/proto/record.pb.go +++ /dev/null @@ -1,506 +0,0 @@ -// Code generated by protoc-gen-gogo. -// source: github.com/containerd/containerd/snapshot/storage/proto/record.proto -// DO NOT EDIT! - -/* - Package proto is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/snapshot/storage/proto/record.proto - - It has these top-level messages: - Snapshot -*/ -package proto - -import proto1 "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import _ "github.com/gogo/protobuf/gogoproto" - -import strings "strings" -import reflect "reflect" - -import io "io" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto1.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto1.GoGoProtoPackageIsVersion2 // please upgrade the proto package - -type Kind int32 - -const ( - KindUnknown Kind = 0 - KindView Kind = 1 - KindActive Kind = 2 - KindCommitted Kind = 3 -) - -var Kind_name = map[int32]string{ - 0: "UNKNOWN", - 1: "VIEW", - 2: "ACTIVE", - 3: "COMMITTED", -} -var Kind_value = map[string]int32{ - "UNKNOWN": 0, - "VIEW": 1, - "ACTIVE": 2, - "COMMITTED": 3, -} - -func (x Kind) String() string { - return proto1.EnumName(Kind_name, int32(x)) -} -func (Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} } - -// Snapshot defines the storage type for a snapshot in the -// metadata store. -type Snapshot struct { - ID uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` - Kind Kind `protobuf:"varint,4,opt,name=kind,proto3,enum=containerd.snapshot.v1.Kind" json:"kind,omitempty"` - // inodes stores the number inodes in use for the snapshot. - // - // Only valid for committed snapshots. - Inodes int64 `protobuf:"varint,6,opt,name=inodes,proto3" json:"inodes,omitempty"` - // Size reports the disk used by the snapshot, excluding the parents. - // - // Only valid for committed snapshots, active snapshots must read the - // current usage from the disk. - Size_ int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size,omitempty"` -} - -func (m *Snapshot) Reset() { *m = Snapshot{} } -func (*Snapshot) ProtoMessage() {} -func (*Snapshot) Descriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} } - -func init() { - proto1.RegisterType((*Snapshot)(nil), "containerd.snapshot.v1.Snapshot") - proto1.RegisterEnum("containerd.snapshot.v1.Kind", Kind_name, Kind_value) -} -func (m *Snapshot) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Snapshot) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.ID != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.ID)) - } - if len(m.Parent) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintRecord(dAtA, i, uint64(len(m.Parent))) - i += copy(dAtA[i:], m.Parent) - } - if m.Kind != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Kind)) - } - if m.Inodes != 0 { - dAtA[i] = 0x30 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Inodes)) - } - if m.Size_ != 0 { - dAtA[i] = 0x38 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Size_)) - } - return i, nil -} - -func encodeFixed64Record(dAtA []byte, offset int, v uint64) int { - dAtA[offset] = uint8(v) - dAtA[offset+1] = uint8(v >> 8) - dAtA[offset+2] = uint8(v >> 16) - dAtA[offset+3] = uint8(v >> 24) - dAtA[offset+4] = uint8(v >> 32) - dAtA[offset+5] = uint8(v >> 40) - dAtA[offset+6] = uint8(v >> 48) - dAtA[offset+7] = uint8(v >> 56) - return offset + 8 -} -func encodeFixed32Record(dAtA []byte, offset int, v uint32) int { - dAtA[offset] = uint8(v) - dAtA[offset+1] = uint8(v >> 8) - dAtA[offset+2] = uint8(v >> 16) - dAtA[offset+3] = uint8(v >> 24) - return offset + 4 -} -func encodeVarintRecord(dAtA []byte, offset int, v uint64) int { - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return offset + 1 -} -func (m *Snapshot) Size() (n int) { - var l int - _ = l - if m.ID != 0 { - n += 1 + sovRecord(uint64(m.ID)) - } - l = len(m.Parent) - if l > 0 { - n += 1 + l + sovRecord(uint64(l)) - } - if m.Kind != 0 { - n += 1 + sovRecord(uint64(m.Kind)) - } - if m.Inodes != 0 { - n += 1 + sovRecord(uint64(m.Inodes)) - } - if m.Size_ != 0 { - n += 1 + sovRecord(uint64(m.Size_)) - } - return n -} - -func sovRecord(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n -} -func sozRecord(x uint64) (n int) { - return sovRecord(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (this *Snapshot) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Snapshot{`, - `ID:` + fmt.Sprintf("%v", this.ID) + `,`, - `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, - `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, - `Inodes:` + fmt.Sprintf("%v", this.Inodes) + `,`, - `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`, - `}`, - }, "") - return s -} -func valueToStringRecord(v interface{}) string { - rv := reflect.ValueOf(v) - if rv.IsNil() { - return "nil" - } - pv := reflect.Indirect(rv).Interface() - return fmt.Sprintf("*%v", pv) -} -func (m *Snapshot) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Snapshot: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Snapshot: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) - } - m.ID = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ID |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Parent", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - 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 ErrInvalidLengthRecord - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Parent = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) - } - m.Kind = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Kind |= (Kind(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Inodes", wireType) - } - m.Inodes = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Inodes |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) - } - m.Size_ = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Size_ |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipRecord(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthRecord - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipRecord(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - return iNdEx, nil - case 1: - iNdEx += 8 - return iNdEx, nil - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - iNdEx += length - if length < 0 { - return 0, ErrInvalidLengthRecord - } - return iNdEx, nil - case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - innerWire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - innerWireType := int(innerWire & 0x7) - if innerWireType == 4 { - break - } - next, err := skipRecord(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil - case 4: - return iNdEx, nil - case 5: - iNdEx += 4 - return iNdEx, nil - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - } - panic("unreachable") -} - -var ( - ErrInvalidLengthRecord = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowRecord = fmt.Errorf("proto: integer overflow") -) - -func init() { - proto1.RegisterFile("github.com/containerd/containerd/snapshot/storage/proto/record.proto", fileDescriptorRecord) -} - -var fileDescriptorRecord = []byte{ - // 364 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xbb, 0xae, 0xd3, 0x30, - 0x18, 0xc7, 0xe3, 0x9c, 0x28, 0xe7, 0xd4, 0x94, 0x12, 0x2c, 0x14, 0x45, 0x51, 0x65, 0x2c, 0xa6, - 0x88, 0x21, 0xe1, 0xf2, 0x04, 0xbd, 0x0d, 0x51, 0xd5, 0x56, 0x0a, 0xbd, 0xcc, 0x69, 0x6c, 0xa5, - 0x56, 0x55, 0xbb, 0x4a, 0x4c, 0x2b, 0x31, 0x31, 0x56, 0x79, 0x02, 0x96, 0x4c, 0xf0, 0x14, 0x3c, - 0x41, 0x47, 0x46, 0x26, 0x44, 0xf3, 0x24, 0x28, 0x69, 0x11, 0x0c, 0x67, 0xfb, 0x5f, 0x7e, 0xf6, - 0xf7, 0xe9, 0x83, 0xc3, 0x94, 0xab, 0xcd, 0xc7, 0xb5, 0x9f, 0xc8, 0x5d, 0x90, 0x48, 0xa1, 0x62, - 0x2e, 0x58, 0x46, 0xff, 0x97, 0xb9, 0x88, 0xf7, 0xf9, 0x46, 0xaa, 0x20, 0x57, 0x32, 0x8b, 0x53, - 0x16, 0xec, 0x33, 0xa9, 0x64, 0x90, 0xb1, 0x44, 0x66, 0xd4, 0x6f, 0x0c, 0xb2, 0xff, 0xf1, 0xfe, - 0x5f, 0xde, 0x3f, 0xbc, 0x75, 0x5f, 0xa4, 0x32, 0x95, 0x57, 0xbe, 0x56, 0x57, 0xfa, 0xd5, 0x17, - 0x00, 0x1f, 0x3e, 0xdc, 0x28, 0x64, 0x43, 0x9d, 0x53, 0x07, 0x10, 0xe0, 0x19, 0x7d, 0xb3, 0xfa, - 0xf5, 0x52, 0x0f, 0x87, 0x91, 0xce, 0x29, 0xb2, 0xa1, 0xb9, 0x8f, 0x33, 0x26, 0x94, 0xa3, 0x13, - 0xe0, 0xb5, 0xa2, 0x9b, 0x43, 0x6f, 0xa0, 0xb1, 0xe5, 0x82, 0x3a, 0x06, 0x01, 0x5e, 0xe7, 0x5d, - 0xd7, 0x7f, 0x7c, 0xb2, 0x3f, 0xe6, 0x82, 0x46, 0x0d, 0x59, 0xff, 0xc4, 0x85, 0xa4, 0x2c, 0x77, - 0x4c, 0x02, 0xbc, 0xbb, 0xe8, 0xe6, 0x10, 0x82, 0x46, 0xce, 0x3f, 0x31, 0xe7, 0xbe, 0x49, 0x1b, - 0xfd, 0xfa, 0x04, 0xa0, 0x51, 0x3f, 0x45, 0x5d, 0x78, 0xbf, 0x98, 0x8e, 0xa7, 0xb3, 0xd5, 0xd4, - 0xd2, 0xdc, 0x67, 0x45, 0x49, 0x9e, 0xd4, 0xf1, 0x42, 0x6c, 0x85, 0x3c, 0x0a, 0x64, 0x43, 0x63, - 0x19, 0x8e, 0x56, 0x16, 0x70, 0xdb, 0x45, 0x49, 0x1e, 0xea, 0x6a, 0xc9, 0xd9, 0x11, 0xb9, 0xd0, - 0xec, 0x0d, 0xe6, 0xe1, 0x72, 0x64, 0xe9, 0x6e, 0xa7, 0x28, 0x09, 0xac, 0x9b, 0x5e, 0xa2, 0xf8, - 0x81, 0x21, 0x02, 0x5b, 0x83, 0xd9, 0x64, 0x12, 0xce, 0xe7, 0xa3, 0xa1, 0x75, 0xe7, 0x3e, 0x2f, - 0x4a, 0xf2, 0xb4, 0xae, 0x07, 0x72, 0xb7, 0xe3, 0x4a, 0x31, 0xea, 0xb6, 0x4f, 0x5f, 0xb1, 0xf6, - 0xfd, 0x1b, 0x6e, 0x36, 0xe8, 0x3b, 0xe7, 0x0b, 0xd6, 0x7e, 0x5e, 0xb0, 0xf6, 0xb9, 0xc2, 0xe0, - 0x5c, 0x61, 0xf0, 0xa3, 0xc2, 0xe0, 0x77, 0x85, 0xc1, 0xda, 0x6c, 0xce, 0xf8, 0xfe, 0x4f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x61, 0xef, 0x92, 0x3d, 0xbc, 0x01, 0x00, 0x00, -} diff --git a/snapshot/storage/proto/record.proto b/snapshot/storage/proto/record.proto deleted file mode 100644 index 50a462a07..000000000 --- a/snapshot/storage/proto/record.proto +++ /dev/null @@ -1,34 +0,0 @@ -syntax = "proto3"; - -package containerd.snapshot.v1; - -import "gogoproto/gogo.proto"; - -enum Kind { - option (gogoproto.goproto_enum_prefix) = false; - option (gogoproto.enum_customname) = "Kind"; - - UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "KindUnknown"]; - VIEW = 1 [(gogoproto.enumvalue_customname) = "KindView"]; - ACTIVE = 2 [(gogoproto.enumvalue_customname) = "KindActive"]; - COMMITTED = 3 [(gogoproto.enumvalue_customname) = "KindCommitted"]; -} - -// Snapshot defines the storage type for a snapshot in the -// metadata store. -message Snapshot { - uint64 id = 1; - string parent = 2; - Kind kind = 4; - - // inodes stores the number inodes in use for the snapshot. - // - // Only valid for committed snapshots. - int64 inodes = 6; - - // Size reports the disk used by the snapshot, excluding the parents. - // - // Only valid for committed snapshots, active snapshots must read the - // current usage from the disk. - int64 size = 7; -} diff --git a/snapshot/testsuite/testsuite.go b/snapshot/testsuite/testsuite.go index 04825a2d1..f06adba68 100644 --- a/snapshot/testsuite/testsuite.go +++ b/snapshot/testsuite/testsuite.go @@ -7,7 +7,9 @@ import ( "os" "path/filepath" "testing" + "time" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/fs/fstest" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/namespaces" @@ -23,6 +25,8 @@ func SnapshotterSuite(t *testing.T, name string, snapshotterFn func(ctx context. t.Run("StatComitted", makeTest(t, name, snapshotterFn, checkSnapshotterStatCommitted)) t.Run("TransitivityTest", makeTest(t, name, snapshotterFn, checkSnapshotterTransitivity)) t.Run("PreareViewFailingtest", makeTest(t, name, snapshotterFn, checkSnapshotterPrepareView)) + t.Run("Update", makeTest(t, name, snapshotterFn, checkUpdate)) + t.Run("Remove", makeTest(t, name, snapshotterFn, checkRemove)) t.Run("LayerFileupdate", makeTest(t, name, snapshotterFn, checkLayerFileUpdate)) t.Run("RemoveDirectoryInLowerLayer", makeTest(t, name, snapshotterFn, checkRemoveDirectoryInLowerLayer)) @@ -414,3 +418,220 @@ func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter assert.NotNil(t, err) } + +// baseTestSnapshots creates a base set of snapshots for tests, each snapshot is empty +// Tests snapshots: +// c1 - committed snapshot, no parent +// c2 - commited snapshot, c1 is parent +// a1 - active snapshot, c2 is parent +// a1 - active snapshot, no parent +// v1 - view snapshot, v1 is parent +// v2 - view snapshot, no parent +func baseTestSnapshots(ctx context.Context, snapshotter snapshot.Snapshotter) error { + if _, err := snapshotter.Prepare(ctx, "c1-a", ""); err != nil { + return err + } + if err := snapshotter.Commit(ctx, "c1", "c1-a"); err != nil { + return err + } + if _, err := snapshotter.Prepare(ctx, "c2-a", "c1"); err != nil { + return err + } + if err := snapshotter.Commit(ctx, "c2", "c2-a"); err != nil { + return err + } + if _, err := snapshotter.Prepare(ctx, "a1", "c2"); err != nil { + return err + } + if _, err := snapshotter.Prepare(ctx, "a2", ""); err != nil { + return err + } + if _, err := snapshotter.View(ctx, "v1", "c2"); err != nil { + return err + } + if _, err := snapshotter.View(ctx, "v2", ""); err != nil { + return err + } + return nil +} + +func checkUpdate(ctx context.Context, t *testing.T, snapshotter snapshot.Snapshotter, work string) { + t1 := time.Now().UTC() + if err := baseTestSnapshots(ctx, snapshotter); err != nil { + t.Fatalf("Failed to create base snapshots: %v", err) + } + t2 := time.Now().UTC() + testcases := []struct { + name string + kind snapshot.Kind + parent string + }{ + { + name: "c1", + kind: snapshot.KindCommitted, + }, + { + name: "c2", + kind: snapshot.KindCommitted, + parent: "c1", + }, + { + name: "a1", + kind: snapshot.KindActive, + parent: "c2", + }, + { + name: "a2", + kind: snapshot.KindActive, + }, + { + name: "v1", + kind: snapshot.KindView, + parent: "c2", + }, + { + name: "v2", + kind: snapshot.KindView, + }, + } + for _, tc := range testcases { + st, err := snapshotter.Stat(ctx, tc.name) + if err != nil { + t.Fatalf("Failed to stat %s: %v", tc.name, err) + } + if st.Created.Before(t1) || st.Created.After(t2) { + t.Errorf("(%s) wrong created time %s: expected between %s and %s", tc.name, st.Created, t1, t2) + continue + } + if st.Created != st.Updated { + t.Errorf("(%s) unexpected updated time %s: expected %s", tc.name, st.Updated, st.Created) + continue + } + if st.Kind != tc.kind { + t.Errorf("(%s) unexpected kind %s, expected %s", tc.name, st.Kind, tc.kind) + continue + } + if st.Parent != tc.parent { + t.Errorf("(%s) unexpected parent %q, expected %q", tc.name, st.Parent, tc.parent) + continue + } + if st.Name != tc.name { + t.Errorf("(%s) unexpected name %q, expected %q", tc.name, st.Name, tc.name) + continue + } + + createdAt := st.Created + expected := map[string]string{ + "l1": "v1", + "l2": "v2", + "l3": "v3", + } + st.Parent = "doesnotexist" + st.Labels = expected + u1 := time.Now().UTC() + st, err = snapshotter.Update(ctx, st) + if err != nil { + t.Fatalf("Failed to update %s: %v", tc.name, err) + } + u2 := time.Now().UTC() + + if st.Created != createdAt { + t.Errorf("(%s) wrong created time %s: expected %s", tc.name, st.Created, createdAt) + continue + } + if st.Updated.Before(u1) || st.Updated.After(u2) { + t.Errorf("(%s) wrong updated time %s: expected between %s and %s", tc.name, st.Updated, u1, u2) + continue + } + if st.Kind != tc.kind { + t.Errorf("(%s) unexpected kind %s, expected %s", tc.name, st.Kind, tc.kind) + continue + } + if st.Parent != tc.parent { + t.Errorf("(%s) unexpected parent %q, expected %q", tc.name, st.Parent, tc.parent) + continue + } + if st.Name != tc.name { + t.Errorf("(%s) unexpected name %q, expected %q", tc.name, st.Name, tc.name) + continue + } + assertLabels(t, st.Labels, expected) + + expected = map[string]string{ + "l1": "updated", + "l3": "v3", + } + st.Labels = map[string]string{ + "l1": "updated", + "l4": "v4", + } + st, err = snapshotter.Update(ctx, st, "labels.l1", "labels.l2") + if err != nil { + t.Fatalf("Failed to update %s: %v", tc.name, err) + } + assertLabels(t, st.Labels, expected) + + expected = map[string]string{ + "l4": "v4", + } + st.Labels = expected + st, err = snapshotter.Update(ctx, st, "labels") + if err != nil { + t.Fatalf("Failed to update %s: %v", tc.name, err) + } + assertLabels(t, st.Labels, expected) + + // Test failure received when providing immutable field path + st.Parent = "doesnotexist" + st, err = snapshotter.Update(ctx, st, "parent") + if err == nil { + t.Errorf("Expected error updating with immutable field path") + } else if !errdefs.IsInvalidArgument(err) { + t.Fatalf("Unexpected error updating %s: %+v", tc.name, err) + } + } +} + +func assertLabels(t *testing.T, actual, expected map[string]string) { + if len(actual) != len(expected) { + t.Fatalf("Label size mismatch: %d vs %d\n\tActual: %#v\n\tExpected: %#v", len(actual), len(expected), actual, expected) + } + for k, v := range expected { + if a := actual[k]; v != a { + t.Errorf("Wrong label value for %s, got %q, expected %q", k, a, v) + } + } + if t.Failed() { + t.FailNow() + } +} + +func checkRemove(ctx context.Context, t *testing.T, snapshotter snapshot.Snapshotter, work string) { + if _, err := snapshotter.Prepare(ctx, "committed-a", ""); err != nil { + t.Fatal(err) + } + if err := snapshotter.Commit(ctx, "committed-1", "committed-a"); err != nil { + t.Fatal(err) + } + if _, err := snapshotter.Prepare(ctx, "reuse-1", "committed-1"); err != nil { + t.Fatal(err) + } + if err := snapshotter.Remove(ctx, "reuse-1"); err != nil { + t.Fatal(err) + } + if _, err := snapshotter.View(ctx, "reuse-1", "committed-1"); err != nil { + t.Fatal(err) + } + if err := snapshotter.Remove(ctx, "reuse-1"); err != nil { + t.Fatal(err) + } + if _, err := snapshotter.Prepare(ctx, "reuse-1", ""); err != nil { + t.Fatal(err) + } + if err := snapshotter.Remove(ctx, "committed-1"); err != nil { + t.Fatal(err) + } + if err := snapshotter.Commit(ctx, "commited-1", "reuse-1"); err != nil { + t.Fatal(err) + } +} diff --git a/snapshot/windows/windows.go b/snapshot/windows/windows.go index 0225ab3d3..d677254fb 100644 --- a/snapshot/windows/windows.go +++ b/snapshot/windows/windows.go @@ -44,15 +44,19 @@ func (o *Snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro panic("not implemented") } +func (o *Snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + panic("not implemented") +} + func (o *Snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { panic("not implemented") } -func (o *Snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { +func (o *Snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { panic("not implemented") } -func (o *Snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { +func (o *Snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { panic("not implemented") } @@ -64,7 +68,7 @@ func (o *Snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er panic("not implemented") } -func (o *Snapshotter) Commit(ctx context.Context, name, key string) error { +func (o *Snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { panic("not implemented") }