Return image references from the storage package

The image's canonical reference is a name with a digest of the image's
manifest, so in imageService.ImageStatus() and
imageService.ListImages(), divide the image's name list into tagged and
digested values, and if we have names, add canonical versions.

In Server.ContainerStatus(), return the image name as it was given to us
as the image, and the image digested reference as the image reference.

In Server.ListImages(), be sure to only return tagged names in the
RepoTags field.  In Server.ImageStatus(), also return canonical
references in the RepoDigests field.

In Server.PullImage(), be sure that we consistently return the same
image reference for an image, whether we ended up pulling it or not.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai 2017-07-12 12:41:38 -04:00
parent 553979e1fc
commit f3b7065bd8
13 changed files with 265 additions and 126 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/containers/image/copy" "github.com/containers/image/copy"
"github.com/containers/image/docker/reference" "github.com/containers/image/docker/reference"
"github.com/containers/image/image" "github.com/containers/image/image"
"github.com/containers/image/manifest"
"github.com/containers/image/signature" "github.com/containers/image/signature"
istorage "github.com/containers/image/storage" istorage "github.com/containers/image/storage"
"github.com/containers/image/transports/alltransports" "github.com/containers/image/transports/alltransports"
@ -25,12 +26,12 @@ var (
// ImageResult wraps a subset of information about an image: its ID, its names, // ImageResult wraps a subset of information about an image: its ID, its names,
// and the size, if known, or nil if it isn't. // and the size, if known, or nil if it isn't.
type ImageResult struct { type ImageResult struct {
ID string ID string
Names []string Name string
Size *uint64 RepoTags []string
// TODO(runcom): this is an hack for https://github.com/kubernetes-incubator/cri-o/pull/1136 RepoDigests []string
// drop this when we have proper image IDs (as in, image IDs should be just Size *uint64
// the config blog digest which is stable across same images). Digest digest.Digest
ConfigDigest digest.Digest ConfigDigest digest.Digest
} }
@ -47,6 +48,11 @@ type imageService struct {
registries []string registries []string
} }
// sizer knows its size.
type sizer interface {
Size() (int64, error)
}
// ImageServer wraps up various CRI-related activities into a reusable // ImageServer wraps up various CRI-related activities into a reusable
// implementation. // implementation.
type ImageServer interface { type ImageServer interface {
@ -88,6 +94,66 @@ func (svc *imageService) getRef(name string) (types.ImageReference, error) {
return ref, nil return ref, nil
} }
func sortNamesByType(names []string) (bestName string, tags, digests []string) {
for _, name := range names {
if len(name) > 72 && name[len(name)-72:len(name)-64] == "@sha256:" {
digests = append(digests, name)
} else {
tags = append(tags, name)
}
}
if len(digests) > 0 {
bestName = digests[0]
}
if len(tags) > 0 {
bestName = tags[0]
}
return bestName, tags, digests
}
func (svc *imageService) makeRepoDigests(knownRepoDigests, tags []string, imageID string) (imageDigest digest.Digest, repoDigests []string) {
// Look up the image's digest.
img, err := svc.store.Image(imageID)
if err != nil {
return "", knownRepoDigests
}
imageDigest = img.Digest
if imageDigest == "" {
imgDigest, err := svc.store.ImageBigDataDigest(imageID, storage.ImageDigestBigDataKey)
if err != nil || imgDigest == "" {
return "", knownRepoDigests
}
imageDigest = imgDigest
}
// If there are no names to convert to canonical references, we're done.
if len(tags) == 0 {
return imageDigest, knownRepoDigests
}
// We only want to supplement what's already explicitly in the list, so keep track of values
// that we already know.
digestMap := make(map[string]struct{})
repoDigests = knownRepoDigests
for _, repoDigest := range knownRepoDigests {
digestMap[repoDigest] = struct{}{}
}
// For each tagged name, parse the name, and if we can extract a named reference, convert
// it into a canonical reference using the digest and add it to the list.
for _, tag := range tags {
if ref, err2 := reference.ParseAnyReference(tag); err2 == nil {
if name, ok := ref.(reference.Named); ok {
trimmed := reference.TrimNamed(name)
if imageRef, err3 := reference.WithDigest(trimmed, imageDigest); err3 == nil {
if _, ok := digestMap[imageRef.String()]; !ok {
repoDigests = append(repoDigests, imageRef.String())
digestMap[imageRef.String()] = struct{}{}
}
}
}
}
}
return imageDigest, repoDigests
}
func (svc *imageService) ListImages(systemContext *types.SystemContext, filter string) ([]ImageResult, error) { func (svc *imageService) ListImages(systemContext *types.SystemContext, filter string) ([]ImageResult, error) {
results := []ImageResult{} results := []ImageResult{}
if filter != "" { if filter != "" {
@ -96,16 +162,26 @@ func (svc *imageService) ListImages(systemContext *types.SystemContext, filter s
return nil, err return nil, err
} }
if image, err := istorage.Transport.GetStoreImage(svc.store, ref); err == nil { if image, err := istorage.Transport.GetStoreImage(svc.store, ref); err == nil {
img, err := ref.NewImage(systemContext) img, err := ref.NewImageSource(systemContext)
if err != nil { if err != nil {
return nil, err return nil, err
} }
size := imageSize(img) size := imageSize(img)
configDigest, err := imageConfigDigest(img, nil)
img.Close() img.Close()
if err != nil {
return nil, err
}
name, tags, digests := sortNamesByType(image.Names)
imageDigest, repoDigests := svc.makeRepoDigests(digests, tags, image.ID)
results = append(results, ImageResult{ results = append(results, ImageResult{
ID: image.ID, ID: image.ID,
Names: image.Names, Name: name,
Size: size, RepoTags: tags,
RepoDigests: repoDigests,
Size: size,
Digest: imageDigest,
ConfigDigest: configDigest,
}) })
} }
} else { } else {
@ -118,16 +194,26 @@ func (svc *imageService) ListImages(systemContext *types.SystemContext, filter s
if err != nil { if err != nil {
return nil, err return nil, err
} }
img, err := ref.NewImage(systemContext) img, err := ref.NewImageSource(systemContext)
if err != nil { if err != nil {
return nil, err return nil, err
} }
size := imageSize(img) size := imageSize(img)
configDigest, err := imageConfigDigest(img, nil)
img.Close() img.Close()
if err != nil {
return nil, err
}
name, tags, digests := sortNamesByType(image.Names)
imageDigest, repoDigests := svc.makeRepoDigests(digests, tags, image.ID)
results = append(results, ImageResult{ results = append(results, ImageResult{
ID: image.ID, ID: image.ID,
Names: image.Names, Name: name,
Size: size, RepoTags: tags,
RepoDigests: repoDigests,
Size: size,
Digest: imageDigest,
ConfigDigest: configDigest,
}) })
} }
} }
@ -152,29 +238,54 @@ func (svc *imageService) ImageStatus(systemContext *types.SystemContext, nameOrI
return nil, err return nil, err
} }
img, err := ref.NewImage(systemContext) img, err := ref.NewImageSource(systemContext)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer img.Close() defer img.Close()
size := imageSize(img) size := imageSize(img)
configDigest, err := imageConfigDigest(img, nil)
if err != nil {
return nil, err
}
return &ImageResult{ name, tags, digests := sortNamesByType(image.Names)
imageDigest, repoDigests := svc.makeRepoDigests(digests, tags, image.ID)
result := ImageResult{
ID: image.ID, ID: image.ID,
Names: image.Names, Name: name,
RepoTags: tags,
RepoDigests: repoDigests,
Size: size, Size: size,
ConfigDigest: img.ConfigInfo().Digest, Digest: imageDigest,
}, nil ConfigDigest: configDigest,
}
return &result, nil
} }
func imageSize(img types.Image) *uint64 { func imageSize(img types.ImageSource) *uint64 {
if sum, err := img.Size(); err == nil { if s, ok := img.(sizer); ok {
usum := uint64(sum) if sum, err := s.Size(); err == nil {
return &usum usum := uint64(sum)
return &usum
}
} }
return nil return nil
} }
func imageConfigDigest(img types.ImageSource, instanceDigest *digest.Digest) (digest.Digest, error) {
manifestBytes, manifestType, err := img.GetManifest(instanceDigest)
if err != nil {
return "", err
}
imgManifest, err := manifest.FromBlob(manifestBytes, manifestType)
if err != nil {
return "", err
}
return imgManifest.ConfigInfo().Digest, nil
}
func (svc *imageService) CanPull(imageName string, options *copy.Options) (bool, error) { func (svc *imageService) CanPull(imageName string, options *copy.Options) (bool, error) {
srcRef, err := svc.prepareReference(imageName, options) srcRef, err := svc.prepareReference(imageName, options)
if err != nil { if err != nil {

View File

@ -14,7 +14,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/docker/distribution/reference"
dockermounts "github.com/docker/docker/pkg/mount" dockermounts "github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/symlink"
@ -963,40 +962,19 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
return nil, err return nil, err
} }
} }
image = images[0]
// Get imageName and imageRef that are requested in container status // Get imageName and imageRef that are later requested in container status
imageName := image status, err := s.StorageImageServer().ImageStatus(s.ImageContext(), images[0])
status, err := s.StorageImageServer().ImageStatus(s.ImageContext(), image)
if err != nil { if err != nil {
return nil, err return nil, err
} }
imageName := status.Name
imageRef := status.ID imageRef := status.ID
// if len(status.RepoDigests) > 0 {
// TODO: https://github.com/kubernetes-incubator/cri-o/issues/531 imageRef = status.RepoDigests[0]
//
//for _, n := range status.Names {
//r, err := reference.ParseNormalizedNamed(n)
//if err != nil {
//return nil, fmt.Errorf("failed to normalize image name for ImageRef: %v", err)
//}
//if digested, isDigested := r.(reference.Canonical); isDigested {
//imageRef = reference.FamiliarString(digested)
//break
//}
//}
for _, n := range status.Names {
r, err := reference.ParseNormalizedNamed(n)
if err != nil {
return nil, fmt.Errorf("failed to normalize image name for Image: %v", err)
}
if tagged, isTagged := r.(reference.Tagged); isTagged {
imageName = reference.FamiliarString(tagged)
break
}
} }
specgen.AddAnnotation(annotations.Image, image)
specgen.AddAnnotation(annotations.ImageName, imageName) specgen.AddAnnotation(annotations.ImageName, imageName)
specgen.AddAnnotation(annotations.ImageRef, imageRef) specgen.AddAnnotation(annotations.ImageRef, imageRef)
specgen.AddAnnotation(annotations.IP, sb.IP()) specgen.AddAnnotation(annotations.IP, sb.IP())
@ -1043,7 +1021,6 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
specgen.AddAnnotation(annotations.TTY, fmt.Sprintf("%v", containerConfig.Tty)) specgen.AddAnnotation(annotations.TTY, fmt.Sprintf("%v", containerConfig.Tty))
specgen.AddAnnotation(annotations.Stdin, fmt.Sprintf("%v", containerConfig.Stdin)) specgen.AddAnnotation(annotations.Stdin, fmt.Sprintf("%v", containerConfig.Stdin))
specgen.AddAnnotation(annotations.StdinOnce, fmt.Sprintf("%v", containerConfig.StdinOnce)) specgen.AddAnnotation(annotations.StdinOnce, fmt.Sprintf("%v", containerConfig.StdinOnce))
specgen.AddAnnotation(annotations.Image, image)
specgen.AddAnnotation(annotations.ResolvPath, sb.InfraContainer().CrioAnnotations()[annotations.ResolvPath]) specgen.AddAnnotation(annotations.ResolvPath, sb.InfraContainer().CrioAnnotations()[annotations.ResolvPath])
created := time.Now() created := time.Now()
@ -1079,7 +1056,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
attempt := metadata.Attempt attempt := metadata.Attempt
containerInfo, err := s.StorageRuntimeServer().CreateContainer(s.ImageContext(), containerInfo, err := s.StorageRuntimeServer().CreateContainer(s.ImageContext(),
sb.Name(), sb.ID(), sb.Name(), sb.ID(),
image, image, image, status.ID,
containerName, containerID, containerName, containerID,
metaname, metaname,
attempt, attempt,

View File

@ -97,6 +97,7 @@ func (s *Server) ListContainers(ctx context.Context, req *pb.ListContainersReque
Metadata: ctr.Metadata(), Metadata: ctr.Metadata(),
Annotations: ctr.Annotations(), Annotations: ctr.Annotations(),
Image: img, Image: img,
ImageRef: ctr.ImageRef(),
} }
switch cState.Status { switch cState.Status {

View File

@ -3,6 +3,7 @@ package server
import ( import (
"time" "time"
"github.com/containers/image/types"
"github.com/kubernetes-incubator/cri-o/oci" "github.com/kubernetes-incubator/cri-o/oci"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -38,7 +39,10 @@ func (s *Server) ContainerStatus(ctx context.Context, req *pb.ContainerStatusReq
ImageRef: c.ImageRef(), ImageRef: c.ImageRef(),
}, },
} }
resp.Status.Image = &pb.ImageSpec{Image: c.ImageName()} resp.Status.Image = &pb.ImageSpec{Image: c.Image()}
if status, err := s.StorageImageServer().ImageStatus(&types.SystemContext{}, c.ImageRef()); err == nil {
resp.Status.Image.Image = status.Name
}
mounts := []*pb.Mount{} mounts := []*pb.Mount{}
for _, cv := range c.Volumes() { for _, cv := range c.Volumes() {

View File

@ -33,14 +33,16 @@ func (s *Server) ListImages(ctx context.Context, req *pb.ListImagesRequest) (res
for _, result := range results { for _, result := range results {
if result.Size != nil { if result.Size != nil {
resp.Images = append(resp.Images, &pb.Image{ resp.Images = append(resp.Images, &pb.Image{
Id: result.ID, Id: result.ID,
RepoTags: result.Names, RepoTags: result.RepoTags,
Size_: *result.Size, RepoDigests: result.RepoDigests,
Size_: *result.Size,
}) })
} else { } else {
resp.Images = append(resp.Images, &pb.Image{ resp.Images = append(resp.Images, &pb.Image{
Id: result.ID, Id: result.ID,
RepoTags: result.Names, RepoTags: result.RepoTags,
RepoDigests: result.RepoDigests,
}) })
} }
} }

View File

@ -104,8 +104,16 @@ func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (resp
if pulled == "" && err != nil { if pulled == "" && err != nil {
return nil, err return nil, err
} }
status, err := s.StorageImageServer().ImageStatus(s.ImageContext(), pulled)
if err != nil {
return nil, err
}
imageRef := status.ID
if len(status.RepoDigests) > 0 {
imageRef = status.RepoDigests[0]
}
resp = &pb.PullImageResponse{ resp = &pb.PullImageResponse{
ImageRef: pulled, ImageRef: imageRef,
} }
logrus.Debugf("PullImageResponse: %+v", resp) logrus.Debugf("PullImageResponse: %+v", resp)
return resp, nil return resp, nil

View File

@ -48,10 +48,10 @@ func (s *Server) ImageStatus(ctx context.Context, req *pb.ImageStatusRequest) (r
} }
resp = &pb.ImageStatusResponse{ resp = &pb.ImageStatusResponse{
Image: &pb.Image{ Image: &pb.Image{
Id: status.ID, Id: status.ID,
RepoTags: status.Names, RepoTags: status.RepoTags,
Size_: *status.Size, RepoDigests: status.RepoDigests,
// TODO: https://github.com/kubernetes-incubator/cri-o/issues/531 Size_: *status.Size,
}, },
} }
logrus.Debugf("ImageStatusResponse: %+v", resp) logrus.Debugf("ImageStatusResponse: %+v", resp)

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
cimage "github.com/containers/image/types"
"github.com/go-zoo/bone" "github.com/go-zoo/bone"
"github.com/kubernetes-incubator/cri-o/lib/sandbox" "github.com/kubernetes-incubator/cri-o/lib/sandbox"
"github.com/kubernetes-incubator/cri-o/oci" "github.com/kubernetes-incubator/cri-o/oci"
@ -45,10 +46,17 @@ func (s *Server) getContainerInfo(id string, getContainerFunc func(id string) *o
logrus.Debugf("can't find sandbox %s for container %s", ctr.Sandbox(), id) logrus.Debugf("can't find sandbox %s for container %s", ctr.Sandbox(), id)
return types.ContainerInfo{}, errSandboxNotFound return types.ContainerInfo{}, errSandboxNotFound
} }
image := ctr.Image()
if s.ContainerServer != nil && s.ContainerServer.StorageImageServer() != nil {
if status, err := s.ContainerServer.StorageImageServer().ImageStatus(&cimage.SystemContext{}, ctr.ImageRef()); err == nil {
image = status.Name
}
}
return types.ContainerInfo{ return types.ContainerInfo{
Name: ctr.Name(), Name: ctr.Name(),
Pid: ctrState.Pid, Pid: ctrState.Pid,
Image: ctr.ImageName(), Image: image,
ImageRef: ctr.ImageRef(),
CreatedTime: ctrState.Created.UnixNano(), CreatedTime: ctrState.Created.UnixNano(),
Labels: ctr.Labels(), Labels: ctr.Labels(),
Annotations: ctr.Annotations(), Annotations: ctr.Annotations(),

View File

@ -67,7 +67,7 @@ func TestGetContainerInfo(t *testing.T) {
"io.kubernetes.test1": "value1", "io.kubernetes.test1": "value1",
} }
getContainerFunc := func(id string) *oci.Container { getContainerFunc := func(id string) *oci.Container {
container, err := oci.NewContainer("testid", "testname", "", "/container/logs", mockNetNS{}, labels, annotations, annotations, "imageName", "imageName", "imageRef", &runtime.ContainerMetadata{}, "testsandboxid", false, false, false, false, false, "/root/for/container", created, "SIGKILL") container, err := oci.NewContainer("testid", "testname", "", "/container/logs", mockNetNS{}, labels, annotations, annotations, "image", "imageName", "imageRef", &runtime.ContainerMetadata{}, "testsandboxid", false, false, false, false, false, "/root/for/container", created, "SIGKILL")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -101,8 +101,11 @@ func TestGetContainerInfo(t *testing.T) {
if ci.Name != "testname" { if ci.Name != "testname" {
t.Fatalf("expected name testname, got %s", ci.Name) t.Fatalf("expected name testname, got %s", ci.Name)
} }
if ci.Image != "imageName" { if ci.Image != "image" {
t.Fatalf("expected image name imageName, got %s", ci.Image) t.Fatalf("expected image name image, got %s", ci.Image)
}
if ci.ImageRef != "imageRef" {
t.Fatalf("expected image ref imageRef, got %s", ci.ImageRef)
} }
if ci.Root != "/var/foo/container" { if ci.Root != "/var/foo/container" {
t.Fatalf("expected root to be /var/foo/container, got %s", ci.Root) t.Fatalf("expected root to be /var/foo/container, got %s", ci.Root)

View File

@ -103,7 +103,7 @@ cp "$CONMON_BINARY" "$TESTDIR/conmon"
PATH=$PATH:$TESTDIR PATH=$PATH:$TESTDIR
# Make sure we have a copy of the redis:latest image. # Make sure we have a copy of the redis:alpine image.
if ! [ -d "$ARTIFACTS_PATH"/redis-image ]; then if ! [ -d "$ARTIFACTS_PATH"/redis-image ]; then
mkdir -p "$ARTIFACTS_PATH"/redis-image mkdir -p "$ARTIFACTS_PATH"/redis-image
if ! "$COPYIMG_BINARY" --import-from=docker://redis:alpine --export-to=dir:"$ARTIFACTS_PATH"/redis-image --signature-policy="$INTEGRATION_ROOT"/policy.json ; then if ! "$COPYIMG_BINARY" --import-from=docker://redis:alpine --export-to=dir:"$ARTIFACTS_PATH"/redis-image --signature-policy="$INTEGRATION_ROOT"/policy.json ; then
@ -113,19 +113,6 @@ if ! [ -d "$ARTIFACTS_PATH"/redis-image ]; then
fi fi
fi fi
# TODO: remove the code below for redis digested image id when
# https://github.com/kubernetes-incubator/cri-o/issues/531 is complete
# as the digested reference will be auto-stored when pulling the tag
# above
if ! [ -d "$ARTIFACTS_PATH"/redis-image-digest ]; then
mkdir -p "$ARTIFACTS_PATH"/redis-image-digest
if ! "$COPYIMG_BINARY" --import-from=docker://redis@sha256:03789f402b2ecfb98184bf128d180f398f81c63364948ff1454583b02442f73b --export-to=dir:"$ARTIFACTS_PATH"/redis-image-digest --signature-policy="$INTEGRATION_ROOT"/policy.json ; then
echo "Error pulling docker://redis@sha256:03789f402b2ecfb98184bf128d180f398f81c63364948ff1454583b02442f73b"
rm -fr "$ARTIFACTS_PATH"/redis-image-digest
exit 1
fi
fi
# Make sure we have a copy of the runcom/stderr-test image. # Make sure we have a copy of the runcom/stderr-test image.
if ! [ -d "$ARTIFACTS_PATH"/stderr-test ]; then if ! [ -d "$ARTIFACTS_PATH"/stderr-test ]; then
mkdir -p "$ARTIFACTS_PATH"/stderr-test mkdir -p "$ARTIFACTS_PATH"/stderr-test
@ -226,13 +213,8 @@ function start_crio() {
"$BIN2IMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --source-binary "$PAUSE_BINARY" "$BIN2IMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --source-binary "$PAUSE_BINARY"
fi fi
"$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=redis:alpine --import-from=dir:"$ARTIFACTS_PATH"/redis-image --add-name=docker.io/library/redis:alpine --signature-policy="$INTEGRATION_ROOT"/policy.json "$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=redis:alpine --import-from=dir:"$ARTIFACTS_PATH"/redis-image --add-name=docker.io/library/redis:alpine --signature-policy="$INTEGRATION_ROOT"/policy.json
# TODO: remove the code below for redis:alpine digested image id when "$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=mrunalp/oom --import-from=dir:"$ARTIFACTS_PATH"/oom-image --add-name=docker.io/mrunalp/oom --signature-policy="$INTEGRATION_ROOT"/policy.json
# https://github.com/kubernetes-incubator/cri-o/issues/531 is complete "$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=mrunalp/image-volume-test --import-from=dir:"$ARTIFACTS_PATH"/image-volume-test-image --add-name=docker.io/mrunalp/image-volume-test --signature-policy="$INTEGRATION_ROOT"/policy.json
# as the digested reference will be auto-stored when pulling the tag
# above
"$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=redis@sha256:03789f402b2ecfb98184bf128d180f398f81c63364948ff1454583b02442f73b --import-from=dir:"$ARTIFACTS_PATH"/redis-image-digest --add-name=docker.io/library/redis@sha256:03789f402b2ecfb98184bf128d180f398f81c63364948ff1454583b02442f73b --signature-policy="$INTEGRATION_ROOT"/policy.json
"$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=mrunalp/oom --import-from=dir:"$ARTIFACTS_PATH"/oom-image --add-name=docker.io/library/mrunalp/oom --signature-policy="$INTEGRATION_ROOT"/policy.json
"$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=mrunalp/image-volume-test --import-from=dir:"$ARTIFACTS_PATH"/image-volume-test-image --add-name=docker.io/library/mrunalp/image-volume-test --signature-policy="$INTEGRATION_ROOT"/policy.json
"$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=busybox:latest --import-from=dir:"$ARTIFACTS_PATH"/busybox-image --add-name=docker.io/library/busybox:latest --signature-policy="$INTEGRATION_ROOT"/policy.json "$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=busybox:latest --import-from=dir:"$ARTIFACTS_PATH"/busybox-image --add-name=docker.io/library/busybox:latest --signature-policy="$INTEGRATION_ROOT"/policy.json
"$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=runcom/stderr-test:latest --import-from=dir:"$ARTIFACTS_PATH"/stderr-test --add-name=docker.io/runcom/stderr-test:latest --signature-policy="$INTEGRATION_ROOT"/policy.json "$COPYIMG_BINARY" --root "$TESTDIR/crio" $STORAGE_OPTIONS --runroot "$TESTDIR/crio-run" --image-name=runcom/stderr-test:latest --import-from=dir:"$ARTIFACTS_PATH"/stderr-test --add-name=docker.io/runcom/stderr-test:latest --signature-policy="$INTEGRATION_ROOT"/policy.json
"$CRIO_BINARY" ${DEFAULT_MOUNTS_OPTS} ${HOOKS_OPTS} --conmon "$CONMON_BINARY" --listen "$CRIO_SOCKET" --cgroup-manager "$CGROUP_MANAGER" --registry "docker.io" --runtime "$RUNTIME_BINARY" --root "$TESTDIR/crio" --runroot "$TESTDIR/crio-run" $STORAGE_OPTIONS --seccomp-profile "$seccomp" --apparmor-profile "$apparmor" --cni-config-dir "$CRIO_CNI_CONFIG" --cni-plugin-dir "$CRIO_CNI_PLUGIN" --signature-policy "$INTEGRATION_ROOT"/policy.json --image-volumes "$IMAGE_VOLUMES" --pids-limit "$PIDS_LIMIT" --enable-shared-pid-namespace=${ENABLE_SHARED_PID_NAMESPACE} --log-size-max "$LOG_SIZE_MAX_LIMIT" --config /dev/null config >$CRIO_CONFIG "$CRIO_BINARY" ${DEFAULT_MOUNTS_OPTS} ${HOOKS_OPTS} --conmon "$CONMON_BINARY" --listen "$CRIO_SOCKET" --cgroup-manager "$CGROUP_MANAGER" --registry "docker.io" --runtime "$RUNTIME_BINARY" --root "$TESTDIR/crio" --runroot "$TESTDIR/crio-run" $STORAGE_OPTIONS --seccomp-profile "$seccomp" --apparmor-profile "$apparmor" --cni-config-dir "$CRIO_CNI_CONFIG" --cni-plugin-dir "$CRIO_CNI_PLUGIN" --signature-policy "$INTEGRATION_ROOT"/policy.json --image-volumes "$IMAGE_VOLUMES" --pids-limit "$PIDS_LIMIT" --enable-shared-pid-namespace=${ENABLE_SHARED_PID_NAMESPACE} --log-size-max "$LOG_SIZE_MAX_LIMIT" --config /dev/null config >$CRIO_CONFIG
@ -252,44 +234,28 @@ function start_crio() {
if [ "$status" -ne 0 ] ; then if [ "$status" -ne 0 ] ; then
crictl pull redis:alpine crictl pull redis:alpine
fi fi
REDIS_IMAGEID=$(crictl inspecti redis:alpine | head -1 | sed -e "s/ID: //g") REDIS_IMAGEID=$(crictl inspecti redis:alpine | grep ^ID: | head -n 1 | sed -e "s/ID: //g")
REDIS_IMAGEREF=$(crictl inspecti redis:alpine | grep ^Digest: | head -n 1 | sed -e "s/Digest: //g")
run crictl inspecti mrunalp/oom run crictl inspecti mrunalp/oom
if [ "$status" -ne 0 ] ; then if [ "$status" -ne 0 ] ; then
crictl pull mrunalp/oom crictl pull mrunalp/oom
fi fi
# OOM_IMAGEID=$(crictl inspecti mrunalp/oom | grep ^ID: | head -n 1 | sed -e "s/ID: //g")
# run crioctl image status --id=runcom/stderr-test
#
# TODO: remove the code below for redis digested image id when
# https://github.com/kubernetes-incubator/cri-o/issues/531 is complete
# as the digested reference will be auto-stored when pulling the tag
# above
#
#
#
REDIS_IMAGEID_DIGESTED="redis@sha256:03789f402b2ecfb98184bf128d180f398f81c63364948ff1454583b02442f73b"
run crictl inspecti $REDIS_IMAGEID_DIGESTED
if [ "$status" -ne 0 ]; then
crictl pull $REDIS_IMAGEID_DIGESTED
fi
#
#
#
run crictl inspecti runcom/stderr-test
if [ "$status" -ne 0 ] ; then if [ "$status" -ne 0 ] ; then
crictl pull runcom/stderr-test:latest crictl pull runcom/stderr-test:latest
fi fi
STDERR_IMAGEID=$(crictl inspecti runcom/stderr-test | head -1 | sed -e "s/ID: //g") STDERR_IMAGEID=$(crictl inspecti runcom/stderr-test | grep ^ID: | head -n 1 | sed -e "s/ID: //g")
run crictl inspecti busybox run crictl inspecti busybox
if [ "$status" -ne 0 ] ; then if [ "$status" -ne 0 ] ; then
crictl pull busybox:latest crictl pull busybox:latest
fi fi
BUSYBOX_IMAGEID=$(crictl inspecti busybox | head -1 | sed -e "s/ID: //g") BUSYBOX_IMAGEID=$(crictl inspecti busybox | grep ^ID: | head -n 1 | sed -e "s/ID: //g")
run crictl inspecti mrunalp/image-volume-test run crictl inspecti mrunalp/image-volume-test
if [ "$status" -ne 0 ] ; then if [ "$status" -ne 0 ] ; then
crictl pull mrunalp/image-volume-test:latest crictl pull mrunalp/image-volume-test:latest
fi fi
VOLUME_IMAGEID=$(crictl inspecti mrunalp/image-volume-test | head -1 | sed -e "s/ID: //g") VOLUME_IMAGEID=$(crictl inspecti mrunalp/image-volume-test | grep ^ID: | head -n 1 | sed -e "s/ID: //g")
} }
function cleanup_ctrs() { function cleanup_ctrs() {

View File

@ -25,7 +25,7 @@ function teardown() {
stop_crio stop_crio
} }
@test "container status return image:tag if created by image ID" { @test "container status when created by image ID" {
start_crio start_crio
run crictl runs "$TESTDATA"/sandbox_config.json run crictl runs "$TESTDATA"/sandbox_config.json
@ -43,16 +43,15 @@ function teardown() {
run crictl inspect "$ctr_id" --output yaml run crictl inspect "$ctr_id" --output yaml
echo "$output" echo "$output"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
[[ "$output" =~ "image: redis:alpine" ]] [[ "$output" =~ "image: docker.io/library/redis:alpine" ]]
[[ "$output" =~ "imageRef: $REDIS_IMAGEREF" ]]
cleanup_ctrs cleanup_ctrs
cleanup_pods cleanup_pods
stop_crio stop_crio
} }
@test "container status return image@digest if created by image ID and digest available" { @test "container status when created by image tagged reference" {
skip "depends on https://github.com/kubernetes-incubator/cri-o/issues/531"
start_crio start_crio
run crictl runs "$TESTDATA"/sandbox_config.json run crictl runs "$TESTDATA"/sandbox_config.json
@ -60,9 +59,9 @@ function teardown() {
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
pod_id="$output" pod_id="$output"
sed -e "s/%VALUE%/$REDIS_IMAGEID_DIGESTED/g" "$TESTDATA"/container_config_by_imageid.json > "$TESTDIR"/ctr_by_imageid.json sed -e "s/%VALUE%/redis:alpine/g" "$TESTDATA"/container_config_by_imageid.json > "$TESTDIR"/ctr_by_imagetag.json
run crictl create "$pod_id" "$TESTDIR"/ctr_by_imageid.json "$TESTDATA"/sandbox_config.json run crictl create "$pod_id" "$TESTDIR"/ctr_by_imagetag.json "$TESTDATA"/sandbox_config.json
echo "$output" echo "$output"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
ctr_id="$output" ctr_id="$output"
@ -70,22 +69,51 @@ function teardown() {
run crictl inspect "$ctr_id" --output yaml run crictl inspect "$ctr_id" --output yaml
echo "$output" echo "$output"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
[[ "$output" =~ "image_ref: redis@sha256:03789f402b2ecfb98184bf128d180f398f81c63364948ff1454583b02442f73b" ]] [[ "$output" =~ "image: docker.io/library/redis:alpine" ]]
[[ "$output" =~ "imageRef: $REDIS_IMAGEREF" ]]
cleanup_ctrs cleanup_ctrs
cleanup_pods cleanup_pods
stop_crio stop_crio
} }
@test "image pull" { @test "container status when created by image canonical reference" {
start_crio
run crictl runs "$TESTDATA"/sandbox_config.json
echo "$output"
[ "$status" -eq 0 ]
pod_id="$output"
sed -e "s|%VALUE%|$REDIS_IMAGEREF|g" "$TESTDATA"/container_config_by_imageid.json > "$TESTDIR"/ctr_by_imageref.json
run crictl create "$pod_id" "$TESTDIR"/ctr_by_imageref.json "$TESTDATA"/sandbox_config.json
echo "$output"
[ "$status" -eq 0 ]
ctr_id="$output"
run crictl inspect "$ctr_id" --output yaml
echo "$output"
[ "$status" -eq 0 ]
[[ "$output" =~ "image: docker.io/library/redis:alpine" ]]
[[ "$output" =~ "imageRef: $REDIS_IMAGEREF" ]]
cleanup_ctrs
cleanup_pods
stop_crio
}
@test "image pull and list" {
start_crio "" "" --no-pause-image start_crio "" "" --no-pause-image
run crictl pull "$IMAGE" run crictl pull "$IMAGE"
echo "$output" echo "$output"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
run crictl inspecti "$IMAGE" run crictl inspecti "$IMAGE"
echo "$output" echo "$output"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
[[ "$output" =~ "$IMAGE" ]] [[ "$output" =~ "$IMAGE" ]]
cleanup_images cleanup_images
stop_crio stop_crio
} }
@ -108,7 +136,33 @@ function teardown() {
stop_crio stop_crio
} }
@test "image pull and list by digest" { @test "image pull and list by tag and ID" {
start_crio "" "" --no-pause-image
run crictl pull "$IMAGE:go"
echo "$output"
[ "$status" -eq 0 ]
run crictl images --quiet "$IMAGE:go"
[ "$status" -eq 0 ]
echo "$output"
[ "$output" != "" ]
imageid="$output"
run crictl images --quiet @"$imageid"
[ "$status" -eq 0 ]
echo "$output"
[ "$output" != "" ]
run crictl images --quiet "$imageid"
[ "$status" -eq 0 ]
echo "$output"
[ "$output" != "" ]
cleanup_images
stop_crio
}
@test "image pull and list by digest and ID" {
start_crio "" "" --no-pause-image start_crio "" "" --no-pause-image
run crictl pull nginx@sha256:33eb1ed1e802d4f71e52421f56af028cdf12bb3bfff5affeaf5bf0e328ffa1bc run crictl pull nginx@sha256:33eb1ed1e802d4f71e52421f56af028cdf12bb3bfff5affeaf5bf0e328ffa1bc
echo "$output" echo "$output"
@ -118,18 +172,20 @@ function teardown() {
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
echo "$output" echo "$output"
[ "$output" != "" ] [ "$output" != "" ]
imageid="$output"
run crictl images --quiet nginx@33eb1ed1e802d4f71e52421f56af028cdf12bb3bfff5affeaf5bf0e328ffa1bc run crictl images --quiet nginx@33eb1ed1e802d4f71e52421f56af028cdf12bb3bfff5affeaf5bf0e328ffa1bc
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
echo "$output" echo "$output"
[ "$output" != "" ] [ "$output" != "" ]
imageid="$output"
run crictl images --quiet @33eb1ed1e802d4f71e52421f56af028cdf12bb3bfff5affeaf5bf0e328ffa1bc run crictl images --quiet @"$imageid"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
echo "$output" echo "$output"
[ "$output" != "" ] [ "$output" != "" ]
run crictl images --quiet 33eb1ed1e802d4f71e52421f56af028cdf12bb3bfff5affeaf5bf0e328ffa1bc run crictl images --quiet "$imageid"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
echo "$output" echo "$output"
[ "$output" != "" ] [ "$output" != "" ]

View File

@ -30,13 +30,15 @@ function teardown() {
out=`echo -e "GET /containers/$ctr_id HTTP/1.1\r\nHost: crio\r\n" | socat - UNIX-CONNECT:$CRIO_SOCKET` out=`echo -e "GET /containers/$ctr_id HTTP/1.1\r\nHost: crio\r\n" | socat - UNIX-CONNECT:$CRIO_SOCKET`
echo "$out" echo "$out"
[[ "$out" =~ "\"sandbox\":\"$pod_id\"" ]] [[ "$out" =~ "\"sandbox\":\"$pod_id\"" ]]
[[ "$out" =~ "\"image\":\"redis:alpine\"" ]] [[ "$out" =~ "\"image\":\"docker.io/library/redis:alpine\"" ]]
[[ "$out" =~ "\"image_ref\":\"$REDIS_IMAGEREF\"" ]]
run crictl inspect --output json "$ctr_id" run crictl inspect --output json "$ctr_id"
echo "$output" echo "$output"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
[[ "$output" =~ "\"id\": \"$ctr_id\"" ]] [[ "$output" =~ "\"id\": \"$ctr_id\"" ]]
[[ "$output" =~ "\"image\": \"redis:alpine\"" ]] [[ "$output" =~ "\"image\": \"docker.io/library/redis:alpine\"" ]]
[[ "$output" =~ "\"imageRef\": \"$REDIS_IMAGEREF\"" ]]
run crictl inspects --output json "$pod_id" run crictl inspects --output json "$pod_id"
echo "$output" echo "$output"

View File

@ -5,6 +5,7 @@ type ContainerInfo struct {
Name string `json:"name"` Name string `json:"name"`
Pid int `json:"pid"` Pid int `json:"pid"`
Image string `json:"image"` Image string `json:"image"`
ImageRef string `json:"image_ref"`
CreatedTime int64 `json:"created_time"` CreatedTime int64 `json:"created_time"`
Labels map[string]string `json:"labels"` Labels map[string]string `json:"labels"`
Annotations map[string]string `json:"annotations"` Annotations map[string]string `json:"annotations"`