2017-03-09 06:03:46 +00:00
|
|
|
package rootfs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
"github.com/docker/containerd"
|
|
|
|
rootfsapi "github.com/docker/containerd/api/services/rootfs"
|
2017-03-10 02:11:26 +00:00
|
|
|
containerd_v1_types "github.com/docker/containerd/api/types/mount"
|
2017-03-09 06:03:46 +00:00
|
|
|
"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"
|
2017-03-16 21:16:29 +00:00
|
|
|
"google.golang.org/grpc/codes"
|
2017-03-09 06:03:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-03-15 06:34:32 +00:00
|
|
|
func (s *Service) Unpack(ctx context.Context, pr *rootfsapi.UnpackRequest) (*rootfsapi.UnpackResponse, error) {
|
2017-03-09 06:03:46 +00:00
|
|
|
layers := make([]ocispec.Descriptor, len(pr.Layers))
|
|
|
|
for i, l := range pr.Layers {
|
|
|
|
layers[i] = ocispec.Descriptor{
|
|
|
|
MediaType: l.MediaType,
|
|
|
|
Digest: l.Digest,
|
2017-03-15 06:34:32 +00:00
|
|
|
Size: l.Size_,
|
2017-03-09 06:03:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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)
|
2017-03-15 06:34:32 +00:00
|
|
|
return &rootfsapi.UnpackResponse{
|
2017-03-09 06:03:46 +00:00
|
|
|
ChainID: chainID,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2017-03-15 06:34:32 +00:00
|
|
|
func (s *Service) Prepare(ctx context.Context, ir *rootfsapi.PrepareRequest) (*rootfsapi.MountResponse, error) {
|
2017-03-10 02:11:26 +00:00
|
|
|
mounts, err := rootfs.InitRootFS(ctx, ir.Name, ir.ChainID, ir.Readonly, s.snapshotter, mounter{})
|
|
|
|
if err != nil {
|
2017-03-16 21:16:29 +00:00
|
|
|
return nil, grpc.Errorf(codes.AlreadyExists, "%v", err)
|
2017-03-10 02:11:26 +00:00
|
|
|
}
|
|
|
|
return &rootfsapi.MountResponse{
|
|
|
|
Mounts: apiMounts(mounts),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) Mounts(ctx context.Context, mr *rootfsapi.MountsRequest) (*rootfsapi.MountResponse, error) {
|
2017-03-15 23:13:15 +00:00
|
|
|
mounts, err := s.snapshotter.Mounts(ctx, mr.Name)
|
2017-03-10 02:11:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &rootfsapi.MountResponse{
|
|
|
|
Mounts: apiMounts(mounts),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func apiMounts(mounts []containerd.Mount) []*containerd_v1_types.Mount {
|
|
|
|
am := make([]*containerd_v1_types.Mount, len(mounts))
|
|
|
|
for i, m := range mounts {
|
|
|
|
am[i] = &containerd_v1_types.Mount{
|
|
|
|
Type: m.Type,
|
|
|
|
Source: m.Source,
|
|
|
|
Options: m.Options,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return am
|
|
|
|
}
|
|
|
|
|
2017-03-09 06:03:46 +00:00
|
|
|
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
|
|
|
|
}
|