Remove load image support
Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
parent
78b4a39f5b
commit
322cd48965
27
Makefile
27
Makefile
@ -39,10 +39,8 @@ help:
|
|||||||
@echo "Usage: make <target>"
|
@echo "Usage: make <target>"
|
||||||
@echo
|
@echo
|
||||||
@echo " * 'install' - Install binaries to system locations"
|
@echo " * 'install' - Install binaries to system locations"
|
||||||
@echo " * 'binaries' - Build containerd and ctr"
|
@echo " * 'binaries' - Build containerd"
|
||||||
@echo " * 'static-binaries - Build static containerd and ctr"
|
@echo " * 'static-binaries - Build static containerd"
|
||||||
@echo " * 'ctr' - Build ctr"
|
|
||||||
@echo " * 'install-ctr' - Install ctr"
|
|
||||||
@echo " * 'containerd' - Build a customized containerd with CRI plugin for testing"
|
@echo " * 'containerd' - Build a customized containerd with CRI plugin for testing"
|
||||||
@echo " * 'install-containerd' - Install customized containerd to system location"
|
@echo " * 'install-containerd' - Install customized containerd to system location"
|
||||||
@echo " * 'release' - Build release tarball"
|
@echo " * 'release' - Build release tarball"
|
||||||
@ -93,13 +91,6 @@ sync-vendor:
|
|||||||
|
|
||||||
update-vendor: sync-vendor sort-vendor
|
update-vendor: sync-vendor sort-vendor
|
||||||
|
|
||||||
$(BUILD_DIR)/ctr: $(SOURCES)
|
|
||||||
$(GO) build -o $@ \
|
|
||||||
-tags '$(BUILD_TAGS)' \
|
|
||||||
-ldflags '$(GO_LDFLAGS)' \
|
|
||||||
-gcflags '$(GO_GCFLAGS)' \
|
|
||||||
$(PROJECT)/cmd/ctr
|
|
||||||
|
|
||||||
$(BUILD_DIR)/containerd: $(SOURCES) $(PLUGIN_SOURCES)
|
$(BUILD_DIR)/containerd: $(SOURCES) $(PLUGIN_SOURCES)
|
||||||
$(GO) build -o $@ \
|
$(GO) build -o $@ \
|
||||||
-tags '$(BUILD_TAGS)' \
|
-tags '$(BUILD_TAGS)' \
|
||||||
@ -128,26 +119,20 @@ test-e2e-node: binaries
|
|||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)/*
|
rm -rf $(BUILD_DIR)/*
|
||||||
|
|
||||||
binaries: $(BUILD_DIR)/containerd $(BUILD_DIR)/ctr
|
binaries: $(BUILD_DIR)/containerd
|
||||||
|
|
||||||
static-binaries: GO_LDFLAGS += -extldflags "-fno-PIC -static"
|
static-binaries: GO_LDFLAGS += -extldflags "-fno-PIC -static"
|
||||||
static-binaries: $(BUILD_DIR)/containerd $(BUILD_DIR)/ctr
|
static-binaries: $(BUILD_DIR)/containerd
|
||||||
|
|
||||||
ctr: $(BUILD_DIR)/ctr
|
|
||||||
|
|
||||||
install-ctr: ctr
|
|
||||||
install -D -m 755 $(BUILD_DIR)/ctr $(BINDIR)/ctr
|
|
||||||
|
|
||||||
containerd: $(BUILD_DIR)/containerd
|
containerd: $(BUILD_DIR)/containerd
|
||||||
|
|
||||||
install-containerd: containerd
|
install-containerd: containerd
|
||||||
install -D -m 755 $(BUILD_DIR)/containerd $(BINDIR)/containerd
|
install -D -m 755 $(BUILD_DIR)/containerd $(BINDIR)/containerd
|
||||||
|
|
||||||
install: install-ctr install-containerd
|
install: install-containerd
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(BINDIR)/containerd
|
rm -f $(BINDIR)/containerd
|
||||||
rm -f $(BINDIR)/ctr
|
|
||||||
|
|
||||||
$(BUILD_DIR)/$(TARBALL): static-binaries vendor.conf
|
$(BUILD_DIR)/$(TARBALL): static-binaries vendor.conf
|
||||||
@BUILD_DIR=$(BUILD_DIR) TARBALL=$(TARBALL) VERSION=$(VERSION) ./hack/release.sh
|
@BUILD_DIR=$(BUILD_DIR) TARBALL=$(TARBALL) VERSION=$(VERSION) ./hack/release.sh
|
||||||
@ -193,8 +178,6 @@ install.tools: .install.gitvalidation .install.gometalinter .install.vndr
|
|||||||
.PHONY: \
|
.PHONY: \
|
||||||
binaries \
|
binaries \
|
||||||
static-binaries \
|
static-binaries \
|
||||||
ctr \
|
|
||||||
install-ctr \
|
|
||||||
containerd \
|
containerd \
|
||||||
install-containerd \
|
install-containerd \
|
||||||
release \
|
release \
|
||||||
|
78
cli/cli.go
78
cli/cli.go
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
gocontext "context"
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
api "github.com/containerd/cri/pkg/api/v1"
|
|
||||||
"github.com/containerd/cri/pkg/client"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Command is the cli command for cri plugin.
|
|
||||||
var Command = cli.Command{
|
|
||||||
Name: "cri",
|
|
||||||
Usage: "interact with cri plugin",
|
|
||||||
Subcommands: cli.Commands{
|
|
||||||
loadCommand,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var loadCommand = cli.Command{
|
|
||||||
Name: "load",
|
|
||||||
Usage: "load one or more images from tar archives.",
|
|
||||||
ArgsUsage: "[flags] TAR [TAR, ...]",
|
|
||||||
Description: "load one or more images from tar archives.",
|
|
||||||
Flags: []cli.Flag{},
|
|
||||||
Action: func(context *cli.Context) error {
|
|
||||||
var (
|
|
||||||
ctx = gocontext.Background()
|
|
||||||
address = context.GlobalString("address")
|
|
||||||
timeout = context.GlobalDuration("timeout")
|
|
||||||
cancel gocontext.CancelFunc
|
|
||||||
)
|
|
||||||
if timeout > 0 {
|
|
||||||
ctx, cancel = gocontext.WithTimeout(gocontext.Background(), timeout)
|
|
||||||
} else {
|
|
||||||
ctx, cancel = gocontext.WithCancel(ctx)
|
|
||||||
}
|
|
||||||
defer cancel()
|
|
||||||
cl, err := client.NewCRIPluginClient(ctx, address)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create grpc client")
|
|
||||||
}
|
|
||||||
for _, path := range context.Args() {
|
|
||||||
absPath, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to get absolute path")
|
|
||||||
}
|
|
||||||
res, err := cl.LoadImage(ctx, &api.LoadImageRequest{FilePath: absPath})
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to load image")
|
|
||||||
}
|
|
||||||
images := res.GetImages()
|
|
||||||
for _, image := range images {
|
|
||||||
fmt.Println("Loaded image:", image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
ctrapp "github.com/containerd/containerd/cmd/ctr/app"
|
|
||||||
|
|
||||||
cricli "github.com/containerd/cri/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
app := ctrapp.New()
|
|
||||||
app.Commands = append(app.Commands, cricli.Command)
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "ctr: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,578 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
|
||||||
// source: api.proto
|
|
||||||
|
|
||||||
/*
|
|
||||||
Package api_v1 is a generated protocol buffer package.
|
|
||||||
|
|
||||||
It is generated from these files:
|
|
||||||
api.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
|
||||||
LoadImageRequest
|
|
||||||
LoadImageResponse
|
|
||||||
*/
|
|
||||||
package api_v1
|
|
||||||
|
|
||||||
import proto "github.com/gogo/protobuf/proto"
|
|
||||||
import fmt "fmt"
|
|
||||||
import math "math"
|
|
||||||
import _ "github.com/gogo/protobuf/gogoproto"
|
|
||||||
|
|
||||||
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 LoadImageRequest struct {
|
|
||||||
// FilePath is the absolute path of docker image tarball.
|
|
||||||
FilePath string `protobuf:"bytes,1,opt,name=FilePath,proto3" json:"FilePath,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *LoadImageRequest) Reset() { *m = LoadImageRequest{} }
|
|
||||||
func (*LoadImageRequest) ProtoMessage() {}
|
|
||||||
func (*LoadImageRequest) Descriptor() ([]byte, []int) { return fileDescriptorApi, []int{0} }
|
|
||||||
|
|
||||||
func (m *LoadImageRequest) GetFilePath() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.FilePath
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoadImageResponse struct {
|
|
||||||
// Images have been loaded.
|
|
||||||
Images []string `protobuf:"bytes,1,rep,name=Images" json:"Images,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *LoadImageResponse) Reset() { *m = LoadImageResponse{} }
|
|
||||||
func (*LoadImageResponse) ProtoMessage() {}
|
|
||||||
func (*LoadImageResponse) Descriptor() ([]byte, []int) { return fileDescriptorApi, []int{1} }
|
|
||||||
|
|
||||||
func (m *LoadImageResponse) GetImages() []string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Images
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
proto.RegisterType((*LoadImageRequest)(nil), "api.v1.LoadImageRequest")
|
|
||||||
proto.RegisterType((*LoadImageResponse)(nil), "api.v1.LoadImageResponse")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 CRIPluginService service
|
|
||||||
|
|
||||||
type CRIPluginServiceClient interface {
|
|
||||||
// LoadImage loads a image into containerd.
|
|
||||||
LoadImage(ctx context.Context, in *LoadImageRequest, opts ...grpc.CallOption) (*LoadImageResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type cRIPluginServiceClient struct {
|
|
||||||
cc *grpc.ClientConn
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCRIPluginServiceClient(cc *grpc.ClientConn) CRIPluginServiceClient {
|
|
||||||
return &cRIPluginServiceClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cRIPluginServiceClient) LoadImage(ctx context.Context, in *LoadImageRequest, opts ...grpc.CallOption) (*LoadImageResponse, error) {
|
|
||||||
out := new(LoadImageResponse)
|
|
||||||
err := grpc.Invoke(ctx, "/api.v1.CRIPluginService/LoadImage", in, out, c.cc, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server API for CRIPluginService service
|
|
||||||
|
|
||||||
type CRIPluginServiceServer interface {
|
|
||||||
// LoadImage loads a image into containerd.
|
|
||||||
LoadImage(context.Context, *LoadImageRequest) (*LoadImageResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterCRIPluginServiceServer(s *grpc.Server, srv CRIPluginServiceServer) {
|
|
||||||
s.RegisterService(&_CRIPluginService_serviceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _CRIPluginService_LoadImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(LoadImageRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(CRIPluginServiceServer).LoadImage(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/api.v1.CRIPluginService/LoadImage",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(CRIPluginServiceServer).LoadImage(ctx, req.(*LoadImageRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _CRIPluginService_serviceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "api.v1.CRIPluginService",
|
|
||||||
HandlerType: (*CRIPluginServiceServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{
|
|
||||||
{
|
|
||||||
MethodName: "LoadImage",
|
|
||||||
Handler: _CRIPluginService_LoadImage_Handler,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Streams: []grpc.StreamDesc{},
|
|
||||||
Metadata: "api.proto",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *LoadImageRequest) 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 *LoadImageRequest) MarshalTo(dAtA []byte) (int, error) {
|
|
||||||
var i int
|
|
||||||
_ = i
|
|
||||||
var l int
|
|
||||||
_ = l
|
|
||||||
if len(m.FilePath) > 0 {
|
|
||||||
dAtA[i] = 0xa
|
|
||||||
i++
|
|
||||||
i = encodeVarintApi(dAtA, i, uint64(len(m.FilePath)))
|
|
||||||
i += copy(dAtA[i:], m.FilePath)
|
|
||||||
}
|
|
||||||
return i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *LoadImageResponse) 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 *LoadImageResponse) MarshalTo(dAtA []byte) (int, error) {
|
|
||||||
var i int
|
|
||||||
_ = i
|
|
||||||
var l int
|
|
||||||
_ = l
|
|
||||||
if len(m.Images) > 0 {
|
|
||||||
for _, s := range m.Images {
|
|
||||||
dAtA[i] = 0xa
|
|
||||||
i++
|
|
||||||
l = len(s)
|
|
||||||
for l >= 1<<7 {
|
|
||||||
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
|
|
||||||
l >>= 7
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
dAtA[i] = uint8(l)
|
|
||||||
i++
|
|
||||||
i += copy(dAtA[i:], s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeVarintApi(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 *LoadImageRequest) Size() (n int) {
|
|
||||||
var l int
|
|
||||||
_ = l
|
|
||||||
l = len(m.FilePath)
|
|
||||||
if l > 0 {
|
|
||||||
n += 1 + l + sovApi(uint64(l))
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *LoadImageResponse) Size() (n int) {
|
|
||||||
var l int
|
|
||||||
_ = l
|
|
||||||
if len(m.Images) > 0 {
|
|
||||||
for _, s := range m.Images {
|
|
||||||
l = len(s)
|
|
||||||
n += 1 + l + sovApi(uint64(l))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func sovApi(x uint64) (n int) {
|
|
||||||
for {
|
|
||||||
n++
|
|
||||||
x >>= 7
|
|
||||||
if x == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
func sozApi(x uint64) (n int) {
|
|
||||||
return sovApi(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
|
||||||
}
|
|
||||||
func (this *LoadImageRequest) String() string {
|
|
||||||
if this == nil {
|
|
||||||
return "nil"
|
|
||||||
}
|
|
||||||
s := strings.Join([]string{`&LoadImageRequest{`,
|
|
||||||
`FilePath:` + fmt.Sprintf("%v", this.FilePath) + `,`,
|
|
||||||
`}`,
|
|
||||||
}, "")
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
func (this *LoadImageResponse) String() string {
|
|
||||||
if this == nil {
|
|
||||||
return "nil"
|
|
||||||
}
|
|
||||||
s := strings.Join([]string{`&LoadImageResponse{`,
|
|
||||||
`Images:` + fmt.Sprintf("%v", this.Images) + `,`,
|
|
||||||
`}`,
|
|
||||||
}, "")
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
func valueToStringApi(v interface{}) string {
|
|
||||||
rv := reflect.ValueOf(v)
|
|
||||||
if rv.IsNil() {
|
|
||||||
return "nil"
|
|
||||||
}
|
|
||||||
pv := reflect.Indirect(rv).Interface()
|
|
||||||
return fmt.Sprintf("*%v", pv)
|
|
||||||
}
|
|
||||||
func (m *LoadImageRequest) 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 ErrIntOverflowApi
|
|
||||||
}
|
|
||||||
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: LoadImageRequest: wiretype end group for non-group")
|
|
||||||
}
|
|
||||||
if fieldNum <= 0 {
|
|
||||||
return fmt.Errorf("proto: LoadImageRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
||||||
}
|
|
||||||
switch fieldNum {
|
|
||||||
case 1:
|
|
||||||
if wireType != 2 {
|
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field FilePath", wireType)
|
|
||||||
}
|
|
||||||
var stringLen uint64
|
|
||||||
for shift := uint(0); ; shift += 7 {
|
|
||||||
if shift >= 64 {
|
|
||||||
return ErrIntOverflowApi
|
|
||||||
}
|
|
||||||
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 ErrInvalidLengthApi
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + intStringLen
|
|
||||||
if postIndex > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.FilePath = string(dAtA[iNdEx:postIndex])
|
|
||||||
iNdEx = postIndex
|
|
||||||
default:
|
|
||||||
iNdEx = preIndex
|
|
||||||
skippy, err := skipApi(dAtA[iNdEx:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if skippy < 0 {
|
|
||||||
return ErrInvalidLengthApi
|
|
||||||
}
|
|
||||||
if (iNdEx + skippy) > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
iNdEx += skippy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if iNdEx > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (m *LoadImageResponse) 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 ErrIntOverflowApi
|
|
||||||
}
|
|
||||||
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: LoadImageResponse: wiretype end group for non-group")
|
|
||||||
}
|
|
||||||
if fieldNum <= 0 {
|
|
||||||
return fmt.Errorf("proto: LoadImageResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
||||||
}
|
|
||||||
switch fieldNum {
|
|
||||||
case 1:
|
|
||||||
if wireType != 2 {
|
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field Images", wireType)
|
|
||||||
}
|
|
||||||
var stringLen uint64
|
|
||||||
for shift := uint(0); ; shift += 7 {
|
|
||||||
if shift >= 64 {
|
|
||||||
return ErrIntOverflowApi
|
|
||||||
}
|
|
||||||
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 ErrInvalidLengthApi
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + intStringLen
|
|
||||||
if postIndex > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.Images = append(m.Images, string(dAtA[iNdEx:postIndex]))
|
|
||||||
iNdEx = postIndex
|
|
||||||
default:
|
|
||||||
iNdEx = preIndex
|
|
||||||
skippy, err := skipApi(dAtA[iNdEx:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if skippy < 0 {
|
|
||||||
return ErrInvalidLengthApi
|
|
||||||
}
|
|
||||||
if (iNdEx + skippy) > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
iNdEx += skippy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if iNdEx > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func skipApi(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, ErrIntOverflowApi
|
|
||||||
}
|
|
||||||
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, ErrIntOverflowApi
|
|
||||||
}
|
|
||||||
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, ErrIntOverflowApi
|
|
||||||
}
|
|
||||||
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, ErrInvalidLengthApi
|
|
||||||
}
|
|
||||||
return iNdEx, nil
|
|
||||||
case 3:
|
|
||||||
for {
|
|
||||||
var innerWire uint64
|
|
||||||
var start int = iNdEx
|
|
||||||
for shift := uint(0); ; shift += 7 {
|
|
||||||
if shift >= 64 {
|
|
||||||
return 0, ErrIntOverflowApi
|
|
||||||
}
|
|
||||||
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 := skipApi(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 (
|
|
||||||
ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling")
|
|
||||||
ErrIntOverflowApi = fmt.Errorf("proto: integer overflow")
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() { proto.RegisterFile("api.proto", fileDescriptorApi) }
|
|
||||||
|
|
||||||
var fileDescriptorApi = []byte{
|
|
||||||
// 219 bytes of a gzipped FileDescriptorProto
|
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4c, 0x2c, 0xc8, 0xd4,
|
|
||||||
0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0x31, 0xcb, 0x0c, 0xa5, 0x74, 0xd3, 0x33, 0x4b,
|
|
||||||
0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0xd3, 0xf3, 0xd3, 0xf3, 0xf5, 0xc1, 0xd2, 0x49,
|
|
||||||
0xa5, 0x69, 0x60, 0x1e, 0x98, 0x03, 0x66, 0x41, 0xb4, 0x29, 0xe9, 0x71, 0x09, 0xf8, 0xe4, 0x27,
|
|
||||||
0xa6, 0x78, 0xe6, 0x26, 0xa6, 0xa7, 0x06, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0x49, 0x71,
|
|
||||||
0x71, 0xb8, 0x65, 0xe6, 0xa4, 0x06, 0x24, 0x96, 0x64, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06,
|
|
||||||
0xc1, 0xf9, 0x4a, 0xda, 0x5c, 0x82, 0x48, 0xea, 0x8b, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85, 0xc4,
|
|
||||||
0xb8, 0xd8, 0xc0, 0x02, 0xc5, 0x12, 0x8c, 0x0a, 0xcc, 0x1a, 0x9c, 0x41, 0x50, 0x9e, 0x51, 0x18,
|
|
||||||
0x97, 0x80, 0x73, 0x90, 0x67, 0x40, 0x4e, 0x69, 0x7a, 0x66, 0x5e, 0x70, 0x6a, 0x51, 0x59, 0x66,
|
|
||||||
0x72, 0xaa, 0x90, 0x13, 0x17, 0x27, 0xdc, 0x00, 0x21, 0x09, 0x3d, 0x88, 0xab, 0xf5, 0xd0, 0xdd,
|
|
||||||
0x20, 0x25, 0x89, 0x45, 0x06, 0x62, 0x9b, 0x12, 0x83, 0x93, 0xcc, 0x89, 0x87, 0x72, 0x8c, 0x37,
|
|
||||||
0x1e, 0xca, 0x31, 0x34, 0x3c, 0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6,
|
|
||||||
0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0xfb, 0xcc, 0x18, 0x10, 0x00,
|
|
||||||
0x00, 0xff, 0xff, 0xfc, 0x6f, 0xec, 0xf4, 0x1d, 0x01, 0x00, 0x00,
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
// To regenerate api.pb.go run `make proto`
|
|
||||||
syntax = 'proto3';
|
|
||||||
|
|
||||||
package api.v1;
|
|
||||||
|
|
||||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
|
||||||
|
|
||||||
option (gogoproto.goproto_stringer_all) = false;
|
|
||||||
option (gogoproto.stringer_all) = true;
|
|
||||||
option (gogoproto.goproto_getters_all) = true;
|
|
||||||
option (gogoproto.marshaler_all) = true;
|
|
||||||
option (gogoproto.sizer_all) = true;
|
|
||||||
option (gogoproto.unmarshaler_all) = true;
|
|
||||||
option (gogoproto.goproto_unrecognized_all) = false;
|
|
||||||
|
|
||||||
// CRIPluginService defines non-CRI APIs for cri plugin.
|
|
||||||
service CRIPluginService{
|
|
||||||
// LoadImage loads a image into containerd.
|
|
||||||
rpc LoadImage(LoadImageRequest) returns (LoadImageResponse) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
message LoadImageRequest {
|
|
||||||
// FilePath is the absolute path of docker image tarball.
|
|
||||||
string FilePath = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message LoadImageResponse {
|
|
||||||
// Images have been loaded.
|
|
||||||
repeated string Images = 1;
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/util"
|
|
||||||
|
|
||||||
api "github.com/containerd/cri/pkg/api/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewCRIPluginClient creates grpc client of cri plugin
|
|
||||||
// TODO(random-liu): Wrap grpc functions.
|
|
||||||
func NewCRIPluginClient(ctx context.Context, endpoint string) (api.CRIPluginServiceClient, error) {
|
|
||||||
addr, dialer, err := util.GetAddressAndDialer(endpoint)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to get dialer")
|
|
||||||
}
|
|
||||||
conn, err := grpc.DialContext(ctx, addr,
|
|
||||||
grpc.WithBlock(),
|
|
||||||
grpc.WithInsecure(),
|
|
||||||
grpc.WithContextDialer(
|
|
||||||
func(ctx context.Context, addr string) (net.Conn, error) {
|
|
||||||
if deadline, ok := ctx.Deadline(); ok {
|
|
||||||
return dialer(addr, time.Until(deadline))
|
|
||||||
}
|
|
||||||
return dialer(addr, 0)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to dial")
|
|
||||||
}
|
|
||||||
return api.NewCRIPluginServiceClient(conn), nil
|
|
||||||
}
|
|
@ -1,356 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package importer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
|
||||||
"github.com/containerd/containerd/content"
|
|
||||||
"github.com/containerd/containerd/errdefs"
|
|
||||||
"github.com/containerd/containerd/images"
|
|
||||||
"github.com/containerd/containerd/leases"
|
|
||||||
"github.com/containerd/containerd/log"
|
|
||||||
"github.com/docker/distribution/reference"
|
|
||||||
"github.com/opencontainers/go-digest"
|
|
||||||
"github.com/opencontainers/image-spec/specs-go"
|
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
ctrdutil "github.com/containerd/cri/pkg/containerd/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This code reuses the docker import code from containerd/containerd#1602.
|
|
||||||
// It has been simplified a bit and garbage collection support was added.
|
|
||||||
// If a library/helper is added to containerd in the future, we should switch to it.
|
|
||||||
|
|
||||||
// manifestDotJSON is an entry in manifest.json.
|
|
||||||
type manifestDotJSON struct {
|
|
||||||
Config string
|
|
||||||
RepoTags []string
|
|
||||||
Layers []string
|
|
||||||
// Parent is unsupported
|
|
||||||
Parent string
|
|
||||||
}
|
|
||||||
|
|
||||||
// isLayerTar returns true if name is like "foobar/layer.tar"
|
|
||||||
func isLayerTar(name string) bool {
|
|
||||||
slashes := len(strings.Split(name, "/"))
|
|
||||||
return slashes == 2 && strings.HasSuffix(name, "/layer.tar")
|
|
||||||
}
|
|
||||||
|
|
||||||
// followSymlinkLayer returns actual layer name of the symlink layer.
|
|
||||||
// It returns "foobar/layer.tar" if the name is like
|
|
||||||
// "../foobar/layer.tar", and returns error if the name
|
|
||||||
// is not in "../foobar/layer.tar" format.
|
|
||||||
func followSymlinkLayer(name string) (string, error) {
|
|
||||||
parts := strings.Split(name, "/")
|
|
||||||
if len(parts) != 3 || parts[0] != ".." {
|
|
||||||
return "", errors.New("invalid symlink layer")
|
|
||||||
}
|
|
||||||
name = strings.TrimPrefix(name, "../")
|
|
||||||
if !isLayerTar(name) {
|
|
||||||
return "", errors.New("invalid layer tar")
|
|
||||||
}
|
|
||||||
return name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isDotJSON returns true if name is like "foobar.json"
|
|
||||||
func isDotJSON(name string) bool {
|
|
||||||
slashes := len(strings.Split(name, "/"))
|
|
||||||
return slashes == 1 && strings.HasSuffix(name, ".json")
|
|
||||||
}
|
|
||||||
|
|
||||||
type imageConfig struct {
|
|
||||||
desc ocispec.Descriptor
|
|
||||||
img ocispec.Image
|
|
||||||
}
|
|
||||||
|
|
||||||
type importConfig struct {
|
|
||||||
unpack bool
|
|
||||||
snapshotter string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImportOption configures import behavior.
|
|
||||||
type ImportOption func(*importConfig)
|
|
||||||
|
|
||||||
// WithUnpack is used to unpack image after import.
|
|
||||||
func WithUnpack(snapshotter string) ImportOption {
|
|
||||||
return func(c *importConfig) {
|
|
||||||
c.unpack = true
|
|
||||||
c.snapshotter = snapshotter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import implements Docker Image Spec v1.1.
|
|
||||||
// An image MUST have `manifest.json`.
|
|
||||||
// `repositories` file in Docker Image Spec v1.0 is not supported (yet).
|
|
||||||
// Also, the current implementation assumes the implicit file name convention,
|
|
||||||
// which is not explicitly documented in the spec. (e.g. foobar/layer.tar)
|
|
||||||
// It returns a group of image references successfully loaded.
|
|
||||||
func Import(ctx context.Context, client *containerd.Client, reader io.Reader, opts ...ImportOption) (_ []string, retErr error) {
|
|
||||||
c := &importConfig{}
|
|
||||||
for _, o := range opts {
|
|
||||||
o(c)
|
|
||||||
}
|
|
||||||
ctx, done, err := client.WithLease(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
deferCtx, deferCancel := ctrdutil.DeferContext()
|
|
||||||
defer deferCancel()
|
|
||||||
if err := done(deferCtx); err != nil {
|
|
||||||
// Get lease id from context still works after context is done.
|
|
||||||
leaseID, _ := leases.FromContext(ctx)
|
|
||||||
log.G(ctx).WithError(err).Errorf("Failed to release lease %q", leaseID)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
cs := client.ContentStore()
|
|
||||||
is := client.ImageService()
|
|
||||||
|
|
||||||
tr := tar.NewReader(reader)
|
|
||||||
var (
|
|
||||||
mfsts []manifestDotJSON
|
|
||||||
symlinkLayers = make(map[string]string) // key: filename (foobar/layer.tar), value: linkname (targetlayerid/layer.tar)
|
|
||||||
layers = make(map[string]ocispec.Descriptor) // key: filename (foobar/layer.tar)
|
|
||||||
configs = make(map[string]imageConfig) // key: filename (foobar.json)
|
|
||||||
)
|
|
||||||
for {
|
|
||||||
hdr, err := tr.Next()
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get next file")
|
|
||||||
}
|
|
||||||
if hdr.Typeflag == tar.TypeSymlink && isLayerTar(hdr.Name) {
|
|
||||||
linkname, err := followSymlinkLayer(hdr.Linkname)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "follow symlink layer from %q to %q", hdr.Name, hdr.Linkname)
|
|
||||||
}
|
|
||||||
symlinkLayers[hdr.Name] = linkname
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if hdr.Typeflag != tar.TypeReg && hdr.Typeflag != tar.TypeRegA {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if hdr.Name == "manifest.json" {
|
|
||||||
mfsts, err = onUntarManifestJSON(tr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "untar manifest %q", hdr.Name)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if isLayerTar(hdr.Name) {
|
|
||||||
desc, err := onUntarLayerTar(ctx, tr, cs, hdr.Name, hdr.Size)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "untar layer %q", hdr.Name)
|
|
||||||
}
|
|
||||||
layers[hdr.Name] = *desc
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if isDotJSON(hdr.Name) {
|
|
||||||
c, err := onUntarDotJSON(ctx, tr, cs, hdr.Name, hdr.Size)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "untar config %q", hdr.Name)
|
|
||||||
}
|
|
||||||
configs[hdr.Name] = *c
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for name, linkname := range symlinkLayers {
|
|
||||||
desc, ok := layers[linkname]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.Errorf("no target for symlink layer from %q to %q", name, linkname)
|
|
||||||
}
|
|
||||||
layers[name] = desc
|
|
||||||
}
|
|
||||||
var refs []string
|
|
||||||
defer func() {
|
|
||||||
if retErr == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO(random-liu): Consider whether we should keep images already imported
|
|
||||||
// even when there is an error.
|
|
||||||
for _, ref := range refs {
|
|
||||||
func() {
|
|
||||||
deferCtx, deferCancel := ctrdutil.DeferContext()
|
|
||||||
defer deferCancel()
|
|
||||||
if err := is.Delete(deferCtx, ref); err != nil {
|
|
||||||
log.G(ctx).WithError(err).Errorf("Failed to remove image %q", ref)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
for _, mfst := range mfsts {
|
|
||||||
config, ok := configs[mfst.Config]
|
|
||||||
if !ok {
|
|
||||||
return refs, errors.Errorf("image config %q not found", mfst.Config)
|
|
||||||
}
|
|
||||||
schema2Manifest, err := makeDockerSchema2Manifest(mfst, config, layers)
|
|
||||||
if err != nil {
|
|
||||||
return refs, errors.Wrap(err, "create docker manifest")
|
|
||||||
}
|
|
||||||
desc, err := writeDockerSchema2Manifest(ctx, cs, *schema2Manifest, config.img.Architecture, config.img.OS)
|
|
||||||
if err != nil {
|
|
||||||
return refs, errors.Wrap(err, "write docker manifest")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ref := range mfst.RepoTags {
|
|
||||||
normalized, err := reference.ParseDockerRef(ref)
|
|
||||||
if err != nil {
|
|
||||||
return refs, errors.Wrapf(err, "normalize image ref %q", ref)
|
|
||||||
}
|
|
||||||
ref = normalized.String()
|
|
||||||
imgrec := images.Image{
|
|
||||||
Name: ref,
|
|
||||||
Target: *desc,
|
|
||||||
}
|
|
||||||
if c.unpack {
|
|
||||||
img := containerd.NewImage(client, imgrec)
|
|
||||||
if err := img.Unpack(ctx, c.snapshotter); err != nil {
|
|
||||||
return refs, errors.Wrapf(err, "unpack image %q", ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := is.Create(ctx, imgrec); err != nil {
|
|
||||||
if !errdefs.IsAlreadyExists(err) {
|
|
||||||
return refs, errors.Wrapf(err, "create image ref %+v", imgrec)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := is.Update(ctx, imgrec)
|
|
||||||
if err != nil {
|
|
||||||
return refs, errors.Wrapf(err, "update image ref %+v", imgrec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refs = append(refs, ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return refs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeDockerSchema2Manifest(mfst manifestDotJSON, config imageConfig, layers map[string]ocispec.Descriptor) (*ocispec.Manifest, error) {
|
|
||||||
manifest := ocispec.Manifest{
|
|
||||||
Versioned: specs.Versioned{
|
|
||||||
SchemaVersion: 2,
|
|
||||||
},
|
|
||||||
Config: config.desc,
|
|
||||||
}
|
|
||||||
for _, f := range mfst.Layers {
|
|
||||||
desc, ok := layers[f]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.Errorf("layer %q not found", f)
|
|
||||||
}
|
|
||||||
manifest.Layers = append(manifest.Layers, desc)
|
|
||||||
}
|
|
||||||
return &manifest, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeDockerSchema2Manifest(ctx context.Context, cs content.Ingester, manifest ocispec.Manifest, arch, os string) (*ocispec.Descriptor, error) {
|
|
||||||
manifestBytes, err := json.Marshal(manifest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
manifestBytesR := bytes.NewReader(manifestBytes)
|
|
||||||
manifestDigest := digest.FromBytes(manifestBytes)
|
|
||||||
labels := map[string]string{}
|
|
||||||
labels["containerd.io/gc.ref.content.0"] = manifest.Config.Digest.String()
|
|
||||||
for i, ch := range manifest.Layers {
|
|
||||||
labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = ch.Digest.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
desc := ocispec.Descriptor{
|
|
||||||
MediaType: images.MediaTypeDockerSchema2Manifest,
|
|
||||||
Digest: manifestDigest,
|
|
||||||
Size: int64(len(manifestBytes)),
|
|
||||||
}
|
|
||||||
if err := content.WriteBlob(ctx, cs, "manifest-"+manifestDigest.String(), manifestBytesR,
|
|
||||||
desc, content.WithLabels(labels)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if arch != "" || os != "" {
|
|
||||||
desc.Platform = &ocispec.Platform{
|
|
||||||
Architecture: arch,
|
|
||||||
OS: os,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &desc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func onUntarManifestJSON(r io.Reader) ([]manifestDotJSON, error) {
|
|
||||||
// name: "manifest.json"
|
|
||||||
b, err := ioutil.ReadAll(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var mfsts []manifestDotJSON
|
|
||||||
if err := json.Unmarshal(b, &mfsts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return mfsts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func onUntarLayerTar(ctx context.Context, r io.Reader, cs content.Ingester, name string, size int64) (*ocispec.Descriptor, error) {
|
|
||||||
// name is like "foobar/layer.tar" ( guaranteed by isLayerTar() )
|
|
||||||
split := strings.Split(name, "/")
|
|
||||||
// note: split[0] is not expected digest here
|
|
||||||
cw, err := cs.Writer(ctx, content.WithRef("layer-"+split[0]), content.WithDescriptor(ocispec.Descriptor{Size: size}))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer cw.Close()
|
|
||||||
if err := content.Copy(ctx, cw, r, size, ""); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &ocispec.Descriptor{
|
|
||||||
MediaType: images.MediaTypeDockerSchema2Layer,
|
|
||||||
Size: size,
|
|
||||||
Digest: cw.Digest(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func onUntarDotJSON(ctx context.Context, r io.Reader, cs content.Ingester, name string, size int64) (*imageConfig, error) {
|
|
||||||
config := imageConfig{}
|
|
||||||
config.desc.MediaType = images.MediaTypeDockerSchema2Config
|
|
||||||
config.desc.Size = size
|
|
||||||
// name is like "foobar.json" ( guaranteed by is DotJSON() )
|
|
||||||
split := strings.Split(name, ".")
|
|
||||||
cw, err := cs.Writer(ctx, content.WithRef("config-"+split[0]), content.WithDescriptor(ocispec.Descriptor{Size: size}))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer cw.Close()
|
|
||||||
var buf bytes.Buffer
|
|
||||||
tr := io.TeeReader(r, &buf)
|
|
||||||
if err := content.Copy(ctx, cw, tr, size, ""); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
config.desc.Digest = cw.Digest()
|
|
||||||
if err := json.Unmarshal(buf.Bytes(), &config.img); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &config, nil
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
api "github.com/containerd/cri/pkg/api/v1"
|
|
||||||
"github.com/containerd/cri/pkg/containerd/importer"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LoadImage loads a image into containerd.
|
|
||||||
func (c *criService) LoadImage(ctx context.Context, r *api.LoadImageRequest) (*api.LoadImageResponse, error) {
|
|
||||||
path := r.GetFilePath()
|
|
||||||
if !filepath.IsAbs(path) {
|
|
||||||
return nil, errors.Errorf("path %q is not an absolute path", path)
|
|
||||||
}
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to open file")
|
|
||||||
}
|
|
||||||
repoTags, err := importer.Import(ctx, c.client, f, importer.WithUnpack(c.config.ContainerdConfig.Snapshotter))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to import image")
|
|
||||||
}
|
|
||||||
for _, repoTag := range repoTags {
|
|
||||||
// Update image store to reflect the newest state in containerd.
|
|
||||||
// Image imported by importer.Import is not treated as managed
|
|
||||||
// by the cri plugin, call `updateImage` to make it managed.
|
|
||||||
// TODO(random-liu): Replace this with the containerd library (issue #909).
|
|
||||||
if err := c.updateImage(ctx, repoTag); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "update image store %q", repoTag)
|
|
||||||
}
|
|
||||||
logrus.Debugf("Imported image %q", repoTag)
|
|
||||||
}
|
|
||||||
return &api.LoadImageResponse{Images: repoTags}, nil
|
|
||||||
}
|
|
@ -23,7 +23,6 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
||||||
|
|
||||||
api "github.com/containerd/cri/pkg/api/v1"
|
|
||||||
ctrdutil "github.com/containerd/cri/pkg/containerd/util"
|
ctrdutil "github.com/containerd/cri/pkg/containerd/util"
|
||||||
"github.com/containerd/cri/pkg/log"
|
"github.com/containerd/cri/pkg/log"
|
||||||
)
|
)
|
||||||
@ -448,21 +447,6 @@ func (in *instrumentedService) UpdateRuntimeConfig(ctx context.Context, r *runti
|
|||||||
return in.c.UpdateRuntimeConfig(ctrdutil.WithNamespace(ctx), r)
|
return in.c.UpdateRuntimeConfig(ctrdutil.WithNamespace(ctx), r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *instrumentedService) LoadImage(ctx context.Context, r *api.LoadImageRequest) (res *api.LoadImageResponse, err error) {
|
|
||||||
if err := in.checkInitialized(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logrus.Debugf("LoadImage from file %q", r.GetFilePath())
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
logrus.WithError(err).Error("LoadImage failed")
|
|
||||||
} else {
|
|
||||||
logrus.Debugf("LoadImage returns images %+v", res.GetImages())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return in.c.LoadImage(ctrdutil.WithNamespace(ctx), r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *instrumentedService) ReopenContainerLog(ctx context.Context, r *runtime.ReopenContainerLogRequest) (res *runtime.ReopenContainerLogResponse, err error) {
|
func (in *instrumentedService) ReopenContainerLog(ctx context.Context, r *runtime.ReopenContainerLogRequest) (res *runtime.ReopenContainerLogResponse, err error) {
|
||||||
if err := in.checkInitialized(); err != nil {
|
if err := in.checkInitialized(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -36,7 +36,6 @@ import (
|
|||||||
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
|
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
|
||||||
|
|
||||||
api "github.com/containerd/cri/pkg/api/v1"
|
|
||||||
"github.com/containerd/cri/pkg/atomic"
|
"github.com/containerd/cri/pkg/atomic"
|
||||||
criconfig "github.com/containerd/cri/pkg/config"
|
criconfig "github.com/containerd/cri/pkg/config"
|
||||||
ctrdutil "github.com/containerd/cri/pkg/containerd/util"
|
ctrdutil "github.com/containerd/cri/pkg/containerd/util"
|
||||||
@ -52,7 +51,6 @@ import (
|
|||||||
type grpcServices interface {
|
type grpcServices interface {
|
||||||
runtime.RuntimeServiceServer
|
runtime.RuntimeServiceServer
|
||||||
runtime.ImageServiceServer
|
runtime.ImageServiceServer
|
||||||
api.CRIPluginServiceServer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CRIService is the interface implement CRI remote service server.
|
// CRIService is the interface implement CRI remote service server.
|
||||||
@ -176,7 +174,6 @@ func (c *criService) Register(s *grpc.Server) error {
|
|||||||
instrumented := newInstrumentedService(c)
|
instrumented := newInstrumentedService(c)
|
||||||
runtime.RegisterRuntimeServiceServer(s, instrumented)
|
runtime.RegisterRuntimeServiceServer(s, instrumented)
|
||||||
runtime.RegisterImageServiceServer(s, instrumented)
|
runtime.RegisterImageServiceServer(s, instrumented)
|
||||||
api.RegisterCRIPluginServiceServer(s, instrumented)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user