From ead425f42619fde0422647c48bf945c747928023 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Wed, 8 Mar 2017 22:03:46 -0800 Subject: [PATCH] Add rootfs service Add rootfs service to allow creation of rootfs from layer array Signed-off-by: Derek McGowan (github: dmcgowan) --- api/services/rootfs/rootfs.pb.go | 577 ++++++++++++++++++++++++++ api/services/rootfs/rootfs.proto | 38 ++ api/types/descriptor/descriptor.pb.go | 417 +++++++++++++++++++ api/types/descriptor/descriptor.proto | 11 + cmd/containerd/builtins.go | 1 + rootfs/apply.go | 19 +- services/rootfs/preparer.go | 39 ++ services/rootfs/service.go | 86 ++++ 8 files changed, 1182 insertions(+), 6 deletions(-) create mode 100644 api/services/rootfs/rootfs.pb.go create mode 100644 api/services/rootfs/rootfs.proto create mode 100644 api/types/descriptor/descriptor.pb.go create mode 100644 api/types/descriptor/descriptor.proto create mode 100644 services/rootfs/preparer.go create mode 100644 services/rootfs/service.go diff --git a/api/services/rootfs/rootfs.pb.go b/api/services/rootfs/rootfs.pb.go new file mode 100644 index 000000000..636205009 --- /dev/null +++ b/api/services/rootfs/rootfs.pb.go @@ -0,0 +1,577 @@ +// Code generated by protoc-gen-gogo. +// source: github.com/docker/containerd/api/services/rootfs/rootfs.proto +// DO NOT EDIT! + +/* + Package rootfs is a generated protocol buffer package. + + It is generated from these files: + github.com/docker/containerd/api/services/rootfs/rootfs.proto + + It has these top-level messages: + PrepareRequest + PrepareResponse +*/ +package rootfs + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" +import _ "github.com/gogo/protobuf/gogoproto" +import _ "github.com/golang/protobuf/ptypes/empty" +import _ "github.com/docker/containerd/api/types/mount" +import containerd_v1_types1 "github.com/docker/containerd/api/types/descriptor" + +import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +import strings "strings" +import reflect "reflect" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.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 _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package + +type PrepareRequest struct { + Layers []*containerd_v1_types1.Descriptor `protobuf:"bytes,1,rep,name=layers" json:"layers,omitempty"` +} + +func (m *PrepareRequest) Reset() { *m = PrepareRequest{} } +func (*PrepareRequest) ProtoMessage() {} +func (*PrepareRequest) Descriptor() ([]byte, []int) { return fileDescriptorRootfs, []int{0} } + +type PrepareResponse struct { + ChainID github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=chainid,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"chainid"` +} + +func (m *PrepareResponse) Reset() { *m = PrepareResponse{} } +func (*PrepareResponse) ProtoMessage() {} +func (*PrepareResponse) Descriptor() ([]byte, []int) { return fileDescriptorRootfs, []int{1} } + +func init() { + proto.RegisterType((*PrepareRequest)(nil), "containerd.v1.PrepareRequest") + proto.RegisterType((*PrepareResponse)(nil), "containerd.v1.PrepareResponse") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for RootFS service + +type RootFSClient interface { + Prepare(ctx context.Context, in *PrepareRequest, opts ...grpc.CallOption) (*PrepareResponse, error) +} + +type rootFSClient struct { + cc *grpc.ClientConn +} + +func NewRootFSClient(cc *grpc.ClientConn) RootFSClient { + return &rootFSClient{cc} +} + +func (c *rootFSClient) Prepare(ctx context.Context, in *PrepareRequest, opts ...grpc.CallOption) (*PrepareResponse, error) { + out := new(PrepareResponse) + err := grpc.Invoke(ctx, "/containerd.v1.RootFS/Prepare", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for RootFS service + +type RootFSServer interface { + Prepare(context.Context, *PrepareRequest) (*PrepareResponse, error) +} + +func RegisterRootFSServer(s *grpc.Server, srv RootFSServer) { + s.RegisterService(&_RootFS_serviceDesc, srv) +} + +func _RootFS_Prepare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PrepareRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RootFSServer).Prepare(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.v1.RootFS/Prepare", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RootFSServer).Prepare(ctx, req.(*PrepareRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _RootFS_serviceDesc = grpc.ServiceDesc{ + ServiceName: "containerd.v1.RootFS", + HandlerType: (*RootFSServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Prepare", + Handler: _RootFS_Prepare_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "github.com/docker/containerd/api/services/rootfs/rootfs.proto", +} + +func (m *PrepareRequest) 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 *PrepareRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Layers) > 0 { + for _, msg := range m.Layers { + dAtA[i] = 0xa + i++ + i = encodeVarintRootfs(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + +func (m *PrepareResponse) 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 *PrepareResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.ChainID) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintRootfs(dAtA, i, uint64(len(m.ChainID))) + i += copy(dAtA[i:], m.ChainID) + } + return i, nil +} + +func encodeFixed64Rootfs(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 encodeFixed32Rootfs(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 encodeVarintRootfs(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 *PrepareRequest) Size() (n int) { + var l int + _ = l + if len(m.Layers) > 0 { + for _, e := range m.Layers { + l = e.Size() + n += 1 + l + sovRootfs(uint64(l)) + } + } + return n +} + +func (m *PrepareResponse) Size() (n int) { + var l int + _ = l + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovRootfs(uint64(l)) + } + return n +} + +func sovRootfs(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozRootfs(x uint64) (n int) { + return sovRootfs(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *PrepareRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PrepareRequest{`, + `Layers:` + strings.Replace(fmt.Sprintf("%v", this.Layers), "Descriptor", "containerd_v1_types1.Descriptor", 1) + `,`, + `}`, + }, "") + return s +} +func (this *PrepareResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PrepareResponse{`, + `ChainID:` + fmt.Sprintf("%v", this.ChainID) + `,`, + `}`, + }, "") + return s +} +func valueToStringRootfs(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *PrepareRequest) 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 ErrIntOverflowRootfs + } + 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: PrepareRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PrepareRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Layers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRootfs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRootfs + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Layers = append(m.Layers, &containerd_v1_types1.Descriptor{}) + if err := m.Layers[len(m.Layers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRootfs(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRootfs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PrepareResponse) 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 ErrIntOverflowRootfs + } + 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: PrepareResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PrepareResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRootfs + } + 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 ErrInvalidLengthRootfs + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainID = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRootfs(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRootfs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipRootfs(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, ErrIntOverflowRootfs + } + 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, ErrIntOverflowRootfs + } + 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, ErrIntOverflowRootfs + } + 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, ErrInvalidLengthRootfs + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRootfs + } + 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 := skipRootfs(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 ( + ErrInvalidLengthRootfs = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRootfs = fmt.Errorf("proto: integer overflow") +) + +func init() { + proto.RegisterFile("github.com/docker/containerd/api/services/rootfs/rootfs.proto", fileDescriptorRootfs) +} + +var fileDescriptorRootfs = []byte{ + // 335 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0xc1, 0x4f, 0xea, 0x40, + 0x10, 0xc6, 0xd9, 0xbc, 0x04, 0xf2, 0xf6, 0xe5, 0xbd, 0x97, 0x34, 0x1e, 0x08, 0xc6, 0x2d, 0xe1, + 0x44, 0x4c, 0xdc, 0x8d, 0x78, 0xd0, 0x0b, 0x17, 0x24, 0x46, 0x6e, 0xa6, 0x1e, 0x3c, 0x97, 0x76, + 0x58, 0x56, 0xa1, 0xb3, 0xee, 0x6e, 0x49, 0xb8, 0xf9, 0xe7, 0x71, 0xf4, 0x68, 0x3c, 0x10, 0xe9, + 0x5f, 0x62, 0x68, 0x0b, 0x82, 0x89, 0xd1, 0x4b, 0x67, 0x9a, 0xef, 0x9b, 0xdf, 0x7c, 0xb3, 0xb4, + 0x2b, 0x95, 0x1b, 0xa7, 0x43, 0x1e, 0xe1, 0x54, 0xc4, 0x18, 0x3d, 0x80, 0x11, 0x11, 0x26, 0x2e, + 0x54, 0x09, 0x98, 0x58, 0x84, 0x5a, 0x09, 0x0b, 0x66, 0xa6, 0x22, 0xb0, 0xc2, 0x20, 0xba, 0xd1, + 0xa6, 0x70, 0x6d, 0xd0, 0xa1, 0xf7, 0xf7, 0xc3, 0xcc, 0x67, 0xa7, 0x8d, 0x03, 0x89, 0x12, 0x73, + 0x45, 0xac, 0xbb, 0xc2, 0xd4, 0x38, 0x94, 0x88, 0x72, 0x02, 0x22, 0xff, 0x1b, 0xa6, 0x23, 0x01, + 0x53, 0xed, 0xe6, 0xa5, 0x78, 0xf1, 0x6d, 0x00, 0x37, 0xd7, 0x60, 0xc5, 0x14, 0xd3, 0xc4, 0x15, + 0xdf, 0x72, 0xb2, 0xf7, 0xc3, 0xc9, 0x18, 0x6c, 0x64, 0x94, 0x76, 0x68, 0x76, 0xda, 0x82, 0xd1, + 0x1a, 0xd0, 0x7f, 0x37, 0x06, 0x74, 0x68, 0x20, 0x80, 0xc7, 0x14, 0xac, 0xf3, 0xce, 0x69, 0x75, + 0x12, 0xce, 0xc1, 0xd8, 0x3a, 0x69, 0xfe, 0x6a, 0xff, 0xe9, 0xf8, 0x7c, 0xef, 0x44, 0x9e, 0x33, + 0x79, 0x7f, 0x0b, 0x0a, 0x4a, 0x7b, 0xeb, 0x9e, 0xfe, 0xdf, 0xa2, 0xac, 0xc6, 0xc4, 0x82, 0x77, + 0x47, 0x6b, 0xd1, 0x38, 0x54, 0x89, 0x8a, 0xeb, 0xa4, 0x49, 0xda, 0xbf, 0x7b, 0xdd, 0xc5, 0xd2, + 0xaf, 0xbc, 0x2e, 0xfd, 0xe3, 0x9d, 0xe8, 0xa8, 0x21, 0xd9, 0xae, 0xb0, 0x42, 0xe2, 0x49, 0xac, + 0x24, 0x58, 0xc7, 0xfb, 0x79, 0xc9, 0x96, 0x7e, 0xed, 0x72, 0x0d, 0x19, 0xf4, 0x83, 0x0d, 0xad, + 0x13, 0xd0, 0x6a, 0x80, 0xe8, 0xae, 0x6e, 0xbd, 0x6b, 0x5a, 0x2b, 0xb7, 0x7a, 0x47, 0x9f, 0x92, + 0xee, 0x1f, 0xd6, 0x60, 0x5f, 0xc9, 0x45, 0xd8, 0x5e, 0x7d, 0xb1, 0x62, 0x95, 0x97, 0x15, 0xab, + 0x3c, 0x65, 0x8c, 0x2c, 0x32, 0x46, 0x9e, 0x33, 0x46, 0xde, 0x32, 0x46, 0x86, 0xd5, 0xfc, 0xad, + 0xce, 0xde, 0x03, 0x00, 0x00, 0xff, 0xff, 0x4c, 0xa2, 0x59, 0x7e, 0x2c, 0x02, 0x00, 0x00, +} diff --git a/api/services/rootfs/rootfs.proto b/api/services/rootfs/rootfs.proto new file mode 100644 index 000000000..866f78a82 --- /dev/null +++ b/api/services/rootfs/rootfs.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; + +package containerd.v1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/empty.proto"; +import "github.com/docker/containerd/api/types/mount/mount.proto"; +import "github.com/docker/containerd/api/types/descriptor/descriptor.proto"; + +service RootFS { + rpc Prepare(PrepareRequest) returns (PrepareResponse); + + // TODO: Add method for initializing and retrieving mounts + //rpc InitMounts(InitRequest) returns (MountResponse); + //rpc Mounts(MountRequest) returns (MountResponse); +} + +message PrepareRequest { + repeated containerd.v1.types.Descriptor layers = 1; +} + +message PrepareResponse { + string chainid = 1 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false, (gogoproto.customname) = "ChainID"]; +} + +//message InitRequest { +// string name = 1; +// string chainID = 2; +// bool Readonly = 3; +//} +// +//message MountRequest { +// string name = 1; +//} +// +//message MountResponse { +// repeated containerd.v1.types.Mount mounts = 1; +//} diff --git a/api/types/descriptor/descriptor.pb.go b/api/types/descriptor/descriptor.pb.go new file mode 100644 index 000000000..6c1b66245 --- /dev/null +++ b/api/types/descriptor/descriptor.pb.go @@ -0,0 +1,417 @@ +// Code generated by protoc-gen-gogo. +// source: github.com/docker/containerd/api/types/descriptor/descriptor.proto +// DO NOT EDIT! + +/* + Package descriptor is a generated protocol buffer package. + + It is generated from these files: + github.com/docker/containerd/api/types/descriptor/descriptor.proto + + It has these top-level messages: + Descriptor +*/ +package descriptor + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" +import _ "github.com/gogo/protobuf/gogoproto" + +import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" + +import strings "strings" +import reflect "reflect" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.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 _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package + +type Descriptor struct { + MediaType string `protobuf:"bytes,1,opt,name=mediaType,proto3" json:"mediaType,omitempty"` + Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,2,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + MediaSize int64 `protobuf:"varint,3,opt,name=mediaSize,proto3" json:"mediaSize,omitempty"` +} + +func (m *Descriptor) Reset() { *m = Descriptor{} } +func (*Descriptor) ProtoMessage() {} +func (*Descriptor) Descriptor() ([]byte, []int) { return fileDescriptorDescriptor, []int{0} } + +func init() { + proto.RegisterType((*Descriptor)(nil), "containerd.v1.types.Descriptor") +} +func (m *Descriptor) 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 *Descriptor) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.MediaType) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintDescriptor(dAtA, i, uint64(len(m.MediaType))) + i += copy(dAtA[i:], m.MediaType) + } + if len(m.Digest) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintDescriptor(dAtA, i, uint64(len(m.Digest))) + i += copy(dAtA[i:], m.Digest) + } + if m.MediaSize != 0 { + dAtA[i] = 0x18 + i++ + i = encodeVarintDescriptor(dAtA, i, uint64(m.MediaSize)) + } + return i, nil +} + +func encodeFixed64Descriptor(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 encodeFixed32Descriptor(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 encodeVarintDescriptor(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 *Descriptor) Size() (n int) { + var l int + _ = l + l = len(m.MediaType) + if l > 0 { + n += 1 + l + sovDescriptor(uint64(l)) + } + l = len(m.Digest) + if l > 0 { + n += 1 + l + sovDescriptor(uint64(l)) + } + if m.MediaSize != 0 { + n += 1 + sovDescriptor(uint64(m.MediaSize)) + } + return n +} + +func sovDescriptor(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozDescriptor(x uint64) (n int) { + return sovDescriptor(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *Descriptor) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Descriptor{`, + `MediaType:` + fmt.Sprintf("%v", this.MediaType) + `,`, + `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`, + `MediaSize:` + fmt.Sprintf("%v", this.MediaSize) + `,`, + `}`, + }, "") + return s +} +func valueToStringDescriptor(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *Descriptor) 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 ErrIntOverflowDescriptor + } + 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: Descriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Descriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MediaType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDescriptor + } + 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 ErrInvalidLengthDescriptor + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MediaType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDescriptor + } + 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 ErrInvalidLengthDescriptor + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MediaSize", wireType) + } + m.MediaSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDescriptor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MediaSize |= (int64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipDescriptor(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthDescriptor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipDescriptor(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, ErrIntOverflowDescriptor + } + 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, ErrIntOverflowDescriptor + } + 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, ErrIntOverflowDescriptor + } + 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, ErrInvalidLengthDescriptor + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDescriptor + } + 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 := skipDescriptor(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 ( + ErrInvalidLengthDescriptor = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowDescriptor = fmt.Errorf("proto: integer overflow") +) + +func init() { + proto.RegisterFile("github.com/docker/containerd/api/types/descriptor/descriptor.proto", fileDescriptorDescriptor) +} + +var fileDescriptorDescriptor = []byte{ + // 230 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x4a, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xc9, 0x4f, 0xce, 0x4e, 0x2d, 0xd2, 0x4f, 0xce, + 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, 0x4a, 0xd1, 0x4f, 0x2c, 0xc8, 0xd4, 0x2f, 0xa9, 0x2c, + 0x48, 0x2d, 0xd6, 0x4f, 0x49, 0x2d, 0x4e, 0x2e, 0xca, 0x2c, 0x28, 0xc9, 0x2f, 0x42, 0x62, 0xea, + 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x23, 0x74, 0xe8, 0x95, 0x19, 0xea, 0x81, 0x35, 0x48, + 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0xe5, 0xf5, 0x41, 0x2c, 0x88, 0x52, 0xa5, 0x29, 0x8c, 0x5c, + 0x5c, 0x2e, 0x70, 0xfd, 0x42, 0x32, 0x5c, 0x9c, 0xb9, 0xa9, 0x29, 0x99, 0x89, 0x21, 0x95, 0x05, + 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x08, 0x01, 0x21, 0x2f, 0x2e, 0xb6, 0x94, 0xcc, + 0xf4, 0xd4, 0xe2, 0x12, 0x09, 0x26, 0x90, 0x94, 0x93, 0xd1, 0x89, 0x7b, 0xf2, 0x0c, 0xb7, 0xee, + 0xc9, 0x6b, 0x21, 0xb9, 0x39, 0xbf, 0x20, 0x35, 0x0f, 0x6e, 0x7d, 0xb1, 0x7e, 0x7a, 0xbe, 0x2e, + 0x44, 0x8b, 0x9e, 0x0b, 0x98, 0x0a, 0x82, 0x9a, 0x00, 0xb7, 0x29, 0x38, 0xb3, 0x2a, 0x55, 0x82, + 0x59, 0x81, 0x51, 0x83, 0x39, 0x08, 0x21, 0xe0, 0x24, 0x71, 0xe2, 0xa1, 0x1c, 0xc3, 0x8d, 0x87, + 0x72, 0x0c, 0x0d, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, + 0x23, 0x39, 0xc6, 0x24, 0x36, 0xb0, 0xbb, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf2, 0x3c, + 0x86, 0x2d, 0x28, 0x01, 0x00, 0x00, +} diff --git a/api/types/descriptor/descriptor.proto b/api/types/descriptor/descriptor.proto new file mode 100644 index 000000000..7a82bd878 --- /dev/null +++ b/api/types/descriptor/descriptor.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package containerd.v1.types; + +import "gogoproto/gogo.proto"; + +message Descriptor { + string mediaType = 1; + string digest = 2 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false]; + int64 mediaSize = 3; +} diff --git a/cmd/containerd/builtins.go b/cmd/containerd/builtins.go index 9620297dd..b5dd21450 100644 --- a/cmd/containerd/builtins.go +++ b/cmd/containerd/builtins.go @@ -7,6 +7,7 @@ import ( _ "github.com/docker/containerd/services/execution" _ "github.com/docker/containerd/services/healthcheck" _ "github.com/docker/containerd/services/metrics" + _ "github.com/docker/containerd/services/rootfs" _ "github.com/docker/containerd/snapshot/btrfs" _ "github.com/docker/containerd/snapshot/overlay" ) diff --git a/rootfs/apply.go b/rootfs/apply.go index e713a2c0a..acbb77c31 100644 --- a/rootfs/apply.go +++ b/rootfs/apply.go @@ -16,9 +16,13 @@ import ( "github.com/pkg/errors" ) +type Preparer interface { + Prepare(ctx context.Context, layers []ocispec.Descriptor) (digest.Digest, error) +} + type Mounter interface { - Mount(mounts ...containerd.Mount) error - Unmount(mounts ...containerd.Mount) error + Mount(target string, mounts ...containerd.Mount) error + Unmount(target string) error } // ApplyLayer applies the layer to the provided parent. The resulting snapshot @@ -51,13 +55,13 @@ func ApplyLayer(snapshots snapshot.Snapshotter, mounter Mounter, rd io.Reader, p return "", err } - if err := mounter.Mount(mounts...); err != nil { + if err := mounter.Mount(dir, mounts...); err != nil { if err := snapshots.Remove(ctx, key); err != nil { log.L.WithError(err).Error("snapshot rollback failed") } return "", err } - defer mounter.Unmount(mounts...) + defer mounter.Unmount(dir) rd, err = dockerarchive.DecompressStream(rd) if err != nil { @@ -74,6 +78,9 @@ func ApplyLayer(snapshots snapshot.Snapshotter, mounter Mounter, rd io.Reader, p if parent != "" { chainID = identity.ChainID([]digest.Digest{parent, chainID}) } + if _, err := snapshots.Stat(ctx, chainID.String()); err == nil { + return diffID, nil //TODO: call snapshots.Remove(ctx, key) once implemented + } return diffID, snapshots.Commit(ctx, chainID.String(), key) } @@ -90,7 +97,7 @@ func Prepare(ctx context.Context, snapshots snapshot.Snapshotter, mounter Mounte // rootfs Controller. // // Just pass them in for now. - openBlob func(digest.Digest) (io.ReadCloser, error), + openBlob func(context.Context, digest.Digest) (io.ReadCloser, error), resolveDiffID func(digest.Digest) digest.Digest, registerDiffID func(diffID, dgst digest.Digest) error) (digest.Digest, error) { var ( @@ -116,7 +123,7 @@ func Prepare(ctx context.Context, snapshots snapshot.Snapshotter, mounter Mounte } } - rc, err := openBlob(layerDigest) + rc, err := openBlob(ctx, layerDigest) if err != nil { return "", err } diff --git a/services/rootfs/preparer.go b/services/rootfs/preparer.go new file mode 100644 index 000000000..40d3c7da0 --- /dev/null +++ b/services/rootfs/preparer.go @@ -0,0 +1,39 @@ +package rootfs + +import ( + "context" + + rootfsapi "github.com/docker/containerd/api/services/rootfs" + containerd_v1_types "github.com/docker/containerd/api/types/descriptor" + "github.com/docker/containerd/rootfs" + digest "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +func NewPreparerFromClient(client rootfsapi.RootFSClient) rootfs.Preparer { + return remotePreparer{ + client: client, + } +} + +type remotePreparer struct { + client rootfsapi.RootFSClient +} + +func (rp remotePreparer) Prepare(ctx context.Context, layers []ocispec.Descriptor) (digest.Digest, error) { + pr := rootfsapi.PrepareRequest{ + Layers: make([]*containerd_v1_types.Descriptor, len(layers)), + } + for i, l := range layers { + pr.Layers[i] = &containerd_v1_types.Descriptor{ + MediaType: l.MediaType, + Digest: l.Digest, + MediaSize: l.Size, + } + } + resp, err := rp.client.Prepare(ctx, &pr) + if err != nil { + return "", nil + } + return resp.ChainID, nil +} diff --git a/services/rootfs/service.go b/services/rootfs/service.go new file mode 100644 index 000000000..817cbf137 --- /dev/null +++ b/services/rootfs/service.go @@ -0,0 +1,86 @@ +package rootfs + +import ( + "syscall" + + "github.com/docker/containerd" + rootfsapi "github.com/docker/containerd/api/services/rootfs" + "github.com/docker/containerd/content" + "github.com/docker/containerd/log" + "github.com/docker/containerd/plugin" + "github.com/docker/containerd/rootfs" + "github.com/docker/containerd/snapshot" + digest "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +func init() { + plugin.Register("rootfs-grpc", &plugin.Registration{ + Type: plugin.GRPCPlugin, + Init: func(ic *plugin.InitContext) (interface{}, error) { + return NewService(ic.Store, ic.Snapshotter) + }, + }) +} + +type Service struct { + store *content.Store + snapshotter snapshot.Snapshotter +} + +func NewService(store *content.Store, snapshotter snapshot.Snapshotter) (*Service, error) { + return &Service{ + store: store, + snapshotter: snapshotter, + }, nil +} + +func (s *Service) Register(gs *grpc.Server) error { + rootfsapi.RegisterRootFSServer(gs, s) + return nil +} + +func (s *Service) Prepare(ctx context.Context, pr *rootfsapi.PrepareRequest) (*rootfsapi.PrepareResponse, error) { + layers := make([]ocispec.Descriptor, len(pr.Layers)) + for i, l := range pr.Layers { + layers[i] = ocispec.Descriptor{ + MediaType: l.MediaType, + Digest: l.Digest, + Size: l.MediaSize, + } + } + log.G(ctx).Infof("Preparing %#v", layers) + chainID, err := rootfs.Prepare(ctx, s.snapshotter, mounter{}, layers, s.store.Reader, emptyResolver, noopRegister) + if err != nil { + log.G(ctx).Errorf("Rootfs Prepare failed!: %v", err) + return nil, err + } + log.G(ctx).Infof("ChainID %#v", chainID) + return &rootfsapi.PrepareResponse{ + ChainID: chainID, + }, nil +} + +type mounter struct{} + +func (mounter) Mount(dir string, mounts ...containerd.Mount) error { + return containerd.MountAll(mounts, dir) +} + +func (mounter) Unmount(dir string) error { + return syscall.Unmount(dir, 0) +} + +func emptyResolver(digest.Digest) digest.Digest { + return digest.Digest("") +} + +func noopRegister(digest.Digest, digest.Digest) error { + return nil +} + +//func (s *Service) Mounts(ctx context.Context, mr *rootfsapi.MountRequest) (*rootfsapi.MountResponse, error) { +// +//}