Add image load.

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu
2017-10-26 05:59:15 +00:00
parent c6fd18ddc3
commit 25fdf72692
20 changed files with 1316 additions and 104 deletions

View File

@@ -43,7 +43,7 @@ import (
"golang.org/x/sys/unix"
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
customopts "github.com/kubernetes-incubator/cri-containerd/pkg/opts"
customopts "github.com/kubernetes-incubator/cri-containerd/pkg/containerd/opts"
cio "github.com/kubernetes-incubator/cri-containerd/pkg/server/io"
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
"github.com/kubernetes-incubator/cri-containerd/pkg/util"

View File

@@ -41,6 +41,7 @@ import (
"github.com/kubernetes-incubator/cri-containerd/pkg/store"
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
"github.com/kubernetes-incubator/cri-containerd/pkg/util"
)
const (
@@ -187,35 +188,6 @@ func criContainerStateToString(state runtime.ContainerState) string {
return runtime.ContainerState_name[int32(state)]
}
// normalizeImageRef normalizes the image reference following the docker convention. This is added
// mainly for backward compatibility.
// The reference returned can only be either tagged or digested. For reference contains both tag
// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@
// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as
// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa.
func normalizeImageRef(ref string) (reference.Named, error) {
named, err := reference.ParseNormalizedNamed(ref)
if err != nil {
return nil, err
}
if _, ok := named.(reference.NamedTagged); ok {
if canonical, ok := named.(reference.Canonical); ok {
// The reference is both tagged and digested, only
// return digested.
newNamed, err := reference.WithName(canonical.Name())
if err != nil {
return nil, err
}
newCanonical, err := reference.WithDigest(newNamed, canonical.Digest())
if err != nil {
return nil, err
}
return newCanonical, nil
}
}
return reference.TagNameOnly(named), nil
}
// getRepoDigestAngTag returns image repoDigest and repoTag of the named image reference.
func getRepoDigestAndTag(namedRef reference.Named, digest imagedigest.Digest, schema1 bool) (string, string) {
var repoTag, repoDigest string
@@ -237,7 +209,7 @@ func (c *criContainerdService) localResolve(ctx context.Context, ref string) (*i
_, err := imagedigest.Parse(ref)
if err != nil {
// ref is not image id, try to resolve it locally.
normalized, err := normalizeImageRef(ref)
normalized, err := util.NormalizeImageRef(ref)
if err != nil {
return nil, fmt.Errorf("invalid image reference %q: %v", ref, err)
}

View File

@@ -19,70 +19,11 @@ package server
import (
"testing"
"github.com/containerd/containerd/reference"
imagedigest "github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert"
)
func TestNormalizeImageRef(t *testing.T) {
for _, test := range []struct {
input string
expect string
}{
{ // has nothing
input: "busybox",
expect: "docker.io/library/busybox:latest",
},
{ // only has tag
input: "busybox:latest",
expect: "docker.io/library/busybox:latest",
},
{ // only has digest
input: "busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582",
expect: "docker.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582",
},
{ // only has path
input: "library/busybox",
expect: "docker.io/library/busybox:latest",
},
{ // only has hostname
input: "docker.io/busybox",
expect: "docker.io/library/busybox:latest",
},
{ // has no tag
input: "docker.io/library/busybox",
expect: "docker.io/library/busybox:latest",
},
{ // has no path
input: "docker.io/busybox:latest",
expect: "docker.io/library/busybox:latest",
},
{ // has no hostname
input: "library/busybox:latest",
expect: "docker.io/library/busybox:latest",
},
{ // full reference
input: "docker.io/library/busybox:latest",
expect: "docker.io/library/busybox:latest",
},
{ // gcr reference
input: "gcr.io/library/busybox",
expect: "gcr.io/library/busybox:latest",
},
{ // both tag and digest
input: "gcr.io/library/busybox:latest@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582",
expect: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582",
},
} {
t.Logf("TestCase %q", test.input)
normalized, err := normalizeImageRef(test.input)
assert.NoError(t, err)
output := normalized.String()
assert.Equal(t, test.expect, output)
_, err = reference.Parse(output)
assert.NoError(t, err, "%q should be containerd supported reference", output)
}
}
"github.com/kubernetes-incubator/cri-containerd/pkg/util"
)
// TestGetUserFromImage tests the logic of getting image uid or user name of image user.
func TestGetUserFromImage(t *testing.T) {
@@ -154,7 +95,7 @@ func TestGetRepoDigestAndTag(t *testing.T) {
},
} {
t.Logf("TestCase %q", desc)
named, err := normalizeImageRef(test.ref)
named, err := util.NormalizeImageRef(test.ref)
assert.NoError(t, err)
repoDigest, repoTag := getRepoDigestAndTag(named, digest, test.schema1)
assert.Equal(t, test.expectedRepoDigest, repoDigest)

78
pkg/server/image_load.go Normal file
View File

@@ -0,0 +1,78 @@
/*
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 (
"fmt"
"golang.org/x/net/context"
"os"
"path/filepath"
"github.com/golang/glog"
api "github.com/kubernetes-incubator/cri-containerd/pkg/api/v1"
"github.com/kubernetes-incubator/cri-containerd/pkg/containerd/importer"
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
)
// LoadImage loads a image into containerd.
func (c *criContainerdService) LoadImage(ctx context.Context, r *api.LoadImageRequest) (*api.LoadImageResponse, error) {
path := r.GetFilePath()
if !filepath.IsAbs(path) {
return nil, fmt.Errorf("path %q is not an absolute path", path)
}
f, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("failed to open file: %v", err)
}
repoTags, err := importer.Import(ctx, c.client.ContentStore(), c.client.ImageService(), f)
if err != nil {
return nil, fmt.Errorf("failed to import image: %v", err)
}
for _, repoTag := range repoTags {
image, err := c.client.GetImage(ctx, repoTag)
if err != nil {
return nil, fmt.Errorf("failed to get image %q: %v", repoTag, err)
}
if err := image.Unpack(ctx, c.config.ContainerdConfig.Snapshotter); err != nil {
glog.Warningf("Failed to unpack image %q: %v", repoTag, err)
// Do not fail image importing. Unpack will be retried when container creation.
}
info, err := getImageInfo(ctx, image, c.client.ContentStore())
if err != nil {
return nil, fmt.Errorf("failed to get image %q info: %v", repoTag, err)
}
id := info.id
if err := c.createImageReference(ctx, id, image.Target()); err != nil {
return nil, fmt.Errorf("failed to create image reference %q: %v", id, err)
}
img := imagestore.Image{
ID: id,
RepoTags: []string{repoTag},
ChainID: info.chainID.String(),
Size: info.size,
Config: &info.config,
Image: image,
}
if err := c.imageStore.Add(img); err != nil {
return nil, fmt.Errorf("failed to add image %q into store: %v", id, err)
}
glog.V(4).Infof("Imported image with id %q, repo tag %q", id, repoTag)
}
return &api.LoadImageResponse{Images: repoTags}, nil
}

View File

@@ -32,6 +32,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
"github.com/kubernetes-incubator/cri-containerd/pkg/util"
)
// For image management:
@@ -75,7 +76,7 @@ import (
// PullImage pulls an image with authentication config.
func (c *criContainerdService) PullImage(ctx context.Context, r *runtime.PullImageRequest) (*runtime.PullImageResponse, error) {
imageRef := r.GetImage().GetImage()
namedRef, err := normalizeImageRef(imageRef)
namedRef, err := util.NormalizeImageRef(imageRef)
if err != nil {
return nil, fmt.Errorf("failed to parse image reference %q: %v", imageRef, err)
}

View File

@@ -20,6 +20,8 @@ import (
"github.com/golang/glog"
"golang.org/x/net/context"
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
api "github.com/kubernetes-incubator/cri-containerd/pkg/api/v1"
)
// instrumentedService wraps service and logs each operation.
@@ -316,3 +318,15 @@ func (in *instrumentedService) ListContainerStats(ctx context.Context, r *runtim
}()
return in.criContainerdService.ListContainerStats(ctx, r)
}
func (in *instrumentedService) LoadImage(ctx context.Context, r *api.LoadImageRequest) (res *api.LoadImageResponse, err error) {
glog.V(4).Infof("LoadImage from file %q", r.GetFilePath())
defer func() {
if err != nil {
glog.Errorf("LoadImage failed, error: %v", err)
} else {
glog.V(4).Infof("LoadImage returns images %+v", res.GetImages())
}
}()
return in.criContainerdService.LoadImage(ctx, r)
}

View File

@@ -33,7 +33,7 @@ import (
"golang.org/x/sys/unix"
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
customopts "github.com/kubernetes-incubator/cri-containerd/pkg/opts"
customopts "github.com/kubernetes-incubator/cri-containerd/pkg/containerd/opts"
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
"github.com/kubernetes-incubator/cri-containerd/pkg/util"
)

View File

@@ -41,6 +41,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
"github.com/kubernetes-incubator/cri-containerd/cmd/cri-containerd/options"
api "github.com/kubernetes-incubator/cri-containerd/pkg/api/v1"
osinterface "github.com/kubernetes-incubator/cri-containerd/pkg/os"
"github.com/kubernetes-incubator/cri-containerd/pkg/registrar"
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
@@ -62,6 +63,7 @@ type CRIContainerdService interface {
Stop()
runtime.RuntimeServiceServer
runtime.ImageServiceServer
api.CRIContainerdServiceServer
}
// criContainerdService implements CRIContainerdService.
@@ -167,8 +169,10 @@ func NewCRIContainerdService(config options.Config) (CRIContainerdService, error
// Create the grpc server and register runtime and image services.
c.server = grpc.NewServer()
runtime.RegisterRuntimeServiceServer(c.server, newInstrumentedService(c))
runtime.RegisterImageServiceServer(c.server, newInstrumentedService(c))
instrumented := newInstrumentedService(c)
runtime.RegisterRuntimeServiceServer(c.server, instrumented)
runtime.RegisterImageServiceServer(c.server, instrumented)
api.RegisterCRIContainerdServiceServer(c.server, instrumented)
return newInstrumentedService(c), nil
}