Skip to content

Commit 8e862f9

Browse files
author
Wei Fu
committedMay 18, 2018
feature: allow use image by digest id
Basically, the user can use sha256:xyz to inspect image or run container. Signed-off-by: Wei Fu <[email protected]>
1 parent 8af60a9 commit 8e862f9

File tree

9 files changed

+78
-24
lines changed

9 files changed

+78
-24
lines changed
 

‎cri/src/cri.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"path"
1010
"path/filepath"
1111
"reflect"
12-
"strings"
1312
"time"
1413

1514
apitypes "github.com/alibaba/pouch/apis/types"
@@ -649,7 +648,7 @@ func (c *CriManager) ContainerStatus(ctx context.Context, r *runtime.ContainerSt
649648
labels, annotations := extractLabels(container.Config.Labels)
650649

651650
imageRef := container.Image
652-
imageInfo, err := c.ImageMgr.GetImage(ctx, strings.TrimPrefix(imageRef, "sha256:"))
651+
imageInfo, err := c.ImageMgr.GetImage(ctx, imageRef)
653652
if err != nil {
654653
return nil, fmt.Errorf("failed to get image %s: %v", imageRef, err)
655654
}
@@ -826,7 +825,7 @@ func (c *CriManager) ListImages(ctx context.Context, r *runtime.ListImagesReques
826825
continue
827826
}
828827
// NOTE: we should query image cache to get the correct image info.
829-
imageInfo, err := c.ImageMgr.GetImage(ctx, strings.TrimPrefix(i.ID, "sha256:"))
828+
imageInfo, err := c.ImageMgr.GetImage(ctx, i.ID)
830829
if err != nil {
831830
continue
832831
}
@@ -850,7 +849,7 @@ func (c *CriManager) ImageStatus(ctx context.Context, r *runtime.ImageStatusRequ
850849
return nil, err
851850
}
852851

853-
imageInfo, err := c.ImageMgr.GetImage(ctx, strings.TrimPrefix(ref.String(), "sha256:"))
852+
imageInfo, err := c.ImageMgr.GetImage(ctx, ref.String())
854853
if err != nil {
855854
// TODO: separate ErrImageNotFound with others.
856855
// Now we just return empty if the error occurred.
@@ -894,7 +893,7 @@ func (c *CriManager) PullImage(ctx context.Context, r *runtime.PullImageRequest)
894893

895894
// RemoveImage removes the image.
896895
func (c *CriManager) RemoveImage(ctx context.Context, r *runtime.RemoveImageRequest) (*runtime.RemoveImageResponse, error) {
897-
imageRef := strings.TrimPrefix(r.GetImage().GetImage(), "sha256:")
896+
imageRef := r.GetImage().GetImage()
898897

899898
if err := c.ImageMgr.RemoveImage(ctx, imageRef, false); err != nil {
900899
if errtypes.IsNotfound(err) {

‎daemon/mgr/container.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import (
3636
"github.com/go-openapi/strfmt"
3737
"github.com/imdario/mergo"
3838
"github.com/magiconair/properties"
39-
digest "github.com/opencontainers/go-digest"
4039
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
4140
"github.com/pkg/errors"
4241
"github.com/sirupsen/logrus"
@@ -1919,7 +1918,7 @@ func (mgr *ContainerManager) getMountPointFromImage(ctx context.Context, meta *C
19191918
var err error
19201919

19211920
// parse volumes from image
1922-
image, err := mgr.ImageMgr.GetImage(ctx, strings.TrimPrefix(meta.Image, digest.Canonical.String()+":"))
1921+
image, err := mgr.ImageMgr.GetImage(ctx, meta.Image)
19231922
if err != nil {
19241923
return errors.Wrapf(err, "failed to get image: %s", meta.Image)
19251924
}

‎daemon/mgr/image.go

+11-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"io"
7+
"strings"
78
"time"
89

910
"github.com/alibaba/pouch/apis/types"
@@ -178,8 +179,11 @@ func (mgr *ImageManager) RemoveImage(ctx context.Context, idOrRef string, force
178179
return err
179180
}
180181

181-
// should remove all the references if the reference is Named Only
182-
if reference.IsNamedOnly(namedRef) {
182+
// should remove all the references if the reference is ID (Named Only)
183+
// or Digest ID (Tagged Named)
184+
if reference.IsNamedOnly(namedRef) ||
185+
strings.HasPrefix(id.String(), namedRef.String()) {
186+
183187
// NOTE: the user maybe use the following references to pull one image
184188
//
185189
// busybox:1.25
@@ -257,9 +261,11 @@ func (mgr *ImageManager) CheckReference(ctx context.Context, idOrRef string) (ac
257261
}
258262
}
259263

260-
// NOTE: if the actualRef is short ID or ID, the primaryRef is first one of
261-
// primary reference
262-
if reference.IsNamedOnly(actualRef) {
264+
// NOTE: if the actualRef is ID (Named Only) or Digest ID (Tagged Named)
265+
// the primaryRef is first one of primary reference
266+
if reference.IsNamedOnly(actualRef) ||
267+
strings.HasPrefix(actualID.String(), actualRef.String()) {
268+
263269
refs := mgr.localStore.GetPrimaryReferences(actualID)
264270
if len(refs) == 0 {
265271
err = errtypes.ErrNotfound

‎daemon/mgr/image_store.go

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package mgr
22

33
import (
4+
"fmt"
5+
"strings"
46
"sync"
57

68
"github.com/alibaba/pouch/pkg/errtypes"
@@ -141,34 +143,41 @@ func (store *imageStore) Search(ref reference.Named) (digest.Digest, reference.N
141143

142144
// if the reference is short ID or ID
143145
//
144-
// NOTE: by default, use the sha256 as the digest algorithm
145-
id, err := store.searchIDs(digest.Canonical.String(), ref.String())
146+
// NOTE: by default, use the sha256 as the digest algorithm if missing
147+
// algorithm header.
148+
id, err := store.searchIDs(ref.String())
146149
if err != nil {
147150
return "", nil, err
148151
}
149152
return id, ref, nil
150153
}
151154

152-
func (store *imageStore) searchIDs(algo string, prefixID string) (digest.Digest, error) {
155+
func (store *imageStore) searchIDs(refID string) (digest.Digest, error) {
153156
var ids []digest.Digest
157+
var id string
158+
159+
id = refID
160+
if !strings.HasPrefix(refID, digest.Canonical.String()) {
161+
id = fmt.Sprintf("%s:%s", digest.Canonical.String(), refID)
162+
}
154163

155164
fn := func(_ patricia.Prefix, item patricia.Item) error {
156165
if got, ok := item.(digest.Digest); ok {
157166
ids = append(ids, got)
158167
}
159168

160169
if len(ids) > 1 {
161-
return pkgerrors.Wrap(errtypes.ErrTooMany, "image: "+prefixID)
170+
return pkgerrors.Wrap(errtypes.ErrTooMany, "image: "+refID)
162171
}
163172
return nil
164173
}
165174

166-
if err := store.idSet.VisitSubtree(patricia.Prefix(algo+":"+prefixID), fn); err != nil {
175+
if err := store.idSet.VisitSubtree(patricia.Prefix(id), fn); err != nil {
167176
return "", err
168177
}
169178

170179
if len(ids) == 0 {
171-
return "", pkgerrors.Wrap(errtypes.ErrNotfound, "image: "+prefixID)
180+
return "", pkgerrors.Wrap(errtypes.ErrNotfound, "image: "+refID)
172181
}
173182
return ids[0], nil
174183
}

‎daemon/mgr/image_store_test.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func TestSearch(t *testing.T) {
112112

113113
// search
114114
{
115-
// should return id if the reference is id
115+
// should return id if the reference is id without algorithm header
116116
{
117117
namedStr := id.Hex()
118118

@@ -127,6 +127,21 @@ func TestSearch(t *testing.T) {
127127
assert.Equal(t, gotRef.String(), namedRef.String())
128128
}
129129

130+
// should return id if the reference is digest id
131+
{
132+
namedStr := id.String()
133+
134+
namedRef, err := reference.Parse(namedStr)
135+
if err != nil {
136+
t.Fatalf("unexpected error during parse reference %v: %v", namedStr, err)
137+
}
138+
139+
gotID, gotRef, err := store.Search(namedRef)
140+
assert.Equal(t, err, nil)
141+
assert.Equal(t, gotID.String(), id.String())
142+
assert.Equal(t, gotRef.String(), namedRef.String())
143+
}
144+
130145
// should return busybox:latest if the reference is busybox
131146
{
132147
namedStr := "busybox"
@@ -202,7 +217,7 @@ func TestSearch(t *testing.T) {
202217

203218
// should return ErrTooMany if the reference is commonPart
204219
{
205-
namedStr := id.Hex()[:20]
220+
namedStr := id.String()[:20]
206221

207222
namedRef, err := reference.Parse(namedStr)
208223
if err != nil {

‎pkg/reference/parse_test.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@ func TestDefaultTagIfMissing(t *testing.T) {
4343
assert.Equal(t, false, strings.Contains(named.String(), "latest"))
4444
}
4545

46-
func TestIsNamedOnly(t *testing.T) {
47-
}
48-
4946
func TestParse(t *testing.T) {
5047
type tCase struct {
5148
name string
@@ -121,6 +118,14 @@ func TestParse(t *testing.T) {
121118
input: "busybox@sha256:1669a6aa7350e1cdd28f972ddad5aceba2912f589f19a090ac",
122119
expected: nil,
123120
err: errors.New("invalid checksum digest length"),
121+
}, {
122+
name: "Digest ID",
123+
input: "sha256:1669a6aa7350e1cdd28f972ddad5aceba2912f589f19a090ac",
124+
expected: taggedReference{
125+
Named: namedReference{"sha256"},
126+
tag: "1669a6aa7350e1cdd28f972ddad5aceba2912f589f19a090ac",
127+
},
128+
err: nil,
124129
},
125130
} {
126131
ref, err := Parse(tc.input)

‎test/api_image_inspect_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ func (suite *APIImageInspectSuite) SetUpTest(c *check.C) {
2626

2727
// TestImageInspectOk tests inspecting images is OK.
2828
func (suite *APIImageInspectSuite) TestImageInspectOk(c *check.C) {
29+
repoID := environment.BusyboxID
2930
repoTag, repoDigest := busyboxImage, fmt.Sprintf("%s@%s", environment.BusyboxRepo, environment.BusyboxDigest)
3031

3132
for _, image := range []string{
33+
repoID,
3234
repoTag,
3335
repoDigest,
3436
fmt.Sprintf("%s:whatever@%s", environment.BusyboxRepo, environment.BusyboxDigest),
@@ -43,7 +45,7 @@ func (suite *APIImageInspectSuite) TestImageInspectOk(c *check.C) {
4345

4446
// TODO: More specific check is needed
4547
c.Assert(got.Config, check.NotNil)
46-
c.Assert(got.ID, check.NotNil)
48+
c.Assert(got.ID, check.Equals, repoID)
4749
c.Assert(got.CreatedAt, check.NotNil)
4850
c.Assert(got.Size, check.NotNil)
4951
c.Assert(reflect.DeepEqual(got.RepoTags, []string{repoTag}), check.Equals, true)

‎test/cli_rmi_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ func (suite *PouchRmiSuite) TestRmiByImageID(c *check.C) {
6464
}
6565
}
6666

67+
// TestRmiByImageDigestID tests "pouch rmi sha256:xxx" work.
68+
func (suite *PouchRmiSuite) TestRmiByImageDigestID(c *check.C) {
69+
command.PouchRun("pull", helloworldImage).Assert(c, icmd.Success)
70+
71+
res := command.PouchRun("images")
72+
res.Assert(c, icmd.Success)
73+
imageID := imagesListToKV(res.Combined())[helloworldImage][0]
74+
75+
command.PouchRun("rmi", "sha256:"+imageID).Assert(c, icmd.Success)
76+
77+
res = command.PouchRun("images").Assert(c, icmd.Success)
78+
if out := res.Combined(); strings.Contains(out, helloworldImage) {
79+
c.Fatalf("unexpected output %s: should rm image %s\n", out, helloworldImage)
80+
}
81+
}
82+
6783
// TestRmiByImageIDWithTwoPrimaryReferences tests "pouch rmi {ID}" work.
6884
func (suite *PouchRmiSuite) TestRmiByImageIDWithTwoPrimaryReferences(c *check.C) {
6985
var (

‎test/environment/env.go

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ var (
2626
// BusyboxRepo the repository of busybox image
2727
BusyboxRepo = "registry.hub.docker.com/library/busybox"
2828

29+
// BusyboxID the digest ID used for busybox image
30+
BusyboxID = "sha256:8ac48589692a53a9b8c2d1ceaa6b402665aa7fe667ba51ccc03002300856d8c7"
31+
2932
// BusyboxTag the tag used for busybox image
3033
BusyboxTag = "1.28"
3134

0 commit comments

Comments
 (0)
Please sign in to comment.