Skip to content

Commit 731743a

Browse files
Add manifestcache push for tag and digest to local repository
Signed-off-by: Raphael Zöllner <[email protected]>
1 parent 259c8a2 commit 731743a

File tree

3 files changed

+131
-10
lines changed

3 files changed

+131
-10
lines changed

src/controller/proxy/controller_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ func (l *localInterfaceMock) PushManifestList(ctx context.Context, repo string,
7474
}
7575

7676
func (l *localInterfaceMock) CheckDependencies(ctx context.Context, repo string, man distribution.Manifest) []distribution.Descriptor {
77-
panic("implement me")
77+
args := l.Called(ctx, repo, man)
78+
return args.Get(0).([]distribution.Descriptor)
7879
}
7980

8081
func (l *localInterfaceMock) DeleteManifest(repo, ref string) {

src/controller/proxy/manifestcache.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package proxy
1616

1717
import (
1818
"context"
19+
"errors"
1920
"fmt"
2021
"strings"
2122
"time"
@@ -28,7 +29,7 @@ import (
2829

2930
"github.com/goharbor/harbor/src/lib"
3031
libCache "github.com/goharbor/harbor/src/lib/cache"
31-
"github.com/goharbor/harbor/src/lib/errors"
32+
libErrors "github.com/goharbor/harbor/src/lib/errors"
3233
"github.com/goharbor/harbor/src/lib/log"
3334
)
3435

@@ -142,7 +143,7 @@ func (m *ManifestListCache) push(ctx context.Context, repo, reference string, ma
142143
}
143144
}
144145
if len(newMan.References()) == 0 {
145-
return errors.New("manifest list doesn't contain any pushed manifest")
146+
return libErrors.New("manifest list doesn't contain any pushed manifest")
146147
}
147148
_, pl, err := newMan.Payload()
148149
if err != nil {
@@ -198,10 +199,30 @@ func (m *ManifestCache) CacheContent(ctx context.Context, remoteRepo string, man
198199
}
199200
}
200201
}
201-
err := m.local.PushManifest(art.Repository, getReference(art), man)
202+
203+
err := m.push(art, man)
202204
if err != nil {
203-
log.Errorf("failed to push manifest, tag: %v, error %v", art.Tag, err)
205+
log.Errorf("error occurred on manifest push to local: %v", err)
206+
}
207+
}
208+
209+
func (m *ManifestCache) push(art lib.ArtifactInfo, man distribution.Manifest) error {
210+
errs := []error{}
211+
if len(art.Digest) > 0 {
212+
err := m.local.PushManifest(art.Repository, art.Digest, man)
213+
if err != nil {
214+
log.Errorf("failed to push manifest referencing digest, tag: %v, digest: %v, error %v", art.Tag, art.Digest, err)
215+
errs = append(errs, err)
216+
}
217+
}
218+
if len(art.Tag) > 0 {
219+
err := m.local.PushManifest(art.Repository, art.Tag, man)
220+
if err != nil {
221+
log.Errorf("failed to push manifest referencing tag, tag: %v, digest: %v, error %v", art.Tag, art.Digest, err)
222+
errs = append(errs, err)
223+
}
204224
}
225+
return errors.Join(errs...)
205226
}
206227

207228
func (m *ManifestCache) putBlobToLocal(remoteRepo string, localRepo string, desc distribution.Descriptor, r RemoteInterface) error {

src/controller/proxy/manifestcache_test.go

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,41 @@ import (
2929
"github.com/goharbor/harbor/src/controller/artifact"
3030
"github.com/goharbor/harbor/src/lib"
3131
"github.com/goharbor/harbor/src/testing/mock"
32+
33+
v1 "github.com/opencontainers/image-spec/specs-go/v1"
3234
)
3335

36+
const ociManifest = `{
37+
"schemaVersion": 2,
38+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
39+
"config": {
40+
"mediaType": "application/vnd.example.config.v1+json",
41+
"digest": "sha256:5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03",
42+
"size": 123
43+
},
44+
"layers": [
45+
{
46+
"mediaType": "application/vnd.example.data.v1.tar+gzip",
47+
"digest": "sha256:e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317",
48+
"size": 1234
49+
}
50+
],
51+
"annotations": {
52+
"com.example.key1": "value1"
53+
}
54+
}`
55+
3456
type CacheTestSuite struct {
3557
suite.Suite
36-
mHandler *ManifestListCache
37-
local localInterfaceMock
58+
mCache *ManifestCache
59+
mListCache *ManifestListCache
60+
local localInterfaceMock
3861
}
3962

4063
func (suite *CacheTestSuite) SetupSuite() {
4164
suite.local = localInterfaceMock{}
42-
suite.mHandler = &ManifestListCache{local: &suite.local}
65+
suite.mListCache = &ManifestListCache{local: &suite.local}
66+
suite.mCache = &ManifestCache{local: &suite.local}
4367
}
4468

4569
func (suite *CacheTestSuite) TearDownSuite() {
@@ -89,7 +113,7 @@ func (suite *CacheTestSuite) TestUpdateManifestList() {
89113
suite.local.On("GetManifest", ctx, artInfo1).Return(ar, nil)
90114
suite.local.On("GetManifest", ctx, mock.Anything).Return(nil, nil)
91115

92-
newMan, err := suite.mHandler.updateManifestList(ctx, "library/hello-world", manList)
116+
newMan, err := suite.mListCache.updateManifestList(ctx, "library/hello-world", manList)
93117
suite.Require().Nil(err)
94118
suite.Assert().Equal(len(newMan.References()), 1)
95119
}
@@ -147,10 +171,85 @@ func (suite *CacheTestSuite) TestPushManifestList() {
147171
suite.local.On("PushManifest", repo, originDigest, mock.Anything).Return(fmt.Errorf("wrong digest"))
148172
suite.local.On("PushManifest", repo, mock.Anything, mock.Anything).Return(nil)
149173

150-
err = suite.mHandler.push(ctx, "library/hello-world", string(originDigest), manList)
174+
err = suite.mListCache.push(ctx, "library/hello-world", string(originDigest), manList)
151175
suite.Require().Nil(err)
152176
}
153177

178+
func (suite *CacheTestSuite) TestManifestCache_CacheContent() {
179+
defer suite.local.AssertExpectations(suite.T())
180+
181+
manifest := ociManifest
182+
man, desc, err := distribution.UnmarshalManifest(v1.MediaTypeImageManifest, []byte(manifest))
183+
suite.Require().NoError(err)
184+
185+
ctx := context.Background()
186+
repo := "library/hello-world"
187+
188+
artInfo := lib.ArtifactInfo{
189+
Repository: repo,
190+
Digest: string(desc.Digest),
191+
Tag: "latest",
192+
}
193+
194+
suite.local.On("CheckDependencies", ctx, artInfo.Repository, man).Once().Return([]distribution.Descriptor{})
195+
suite.local.On("PushManifest", artInfo.Repository, artInfo.Digest, man).Once().Return(nil)
196+
suite.local.On("PushManifest", artInfo.Repository, artInfo.Tag, man).Once().Return(nil)
197+
198+
suite.mCache.CacheContent(ctx, repo, man, artInfo, nil, "")
199+
}
200+
201+
func (suite *CacheTestSuite) TestManifestCache_push_succeeds() {
202+
defer suite.local.AssertExpectations(suite.T())
203+
204+
manifest := ociManifest
205+
man, desc, err := distribution.UnmarshalManifest(v1.MediaTypeImageManifest, []byte(manifest))
206+
suite.Require().NoError(err)
207+
208+
repo := "library/hello-world"
209+
210+
artInfo := lib.ArtifactInfo{
211+
Repository: repo,
212+
Digest: string(desc.Digest),
213+
Tag: "latest",
214+
}
215+
216+
suite.local.On("PushManifest", artInfo.Repository, artInfo.Digest, man).Once().Return(nil)
217+
suite.local.On("PushManifest", artInfo.Repository, artInfo.Tag, man).Once().Return(nil)
218+
219+
err = suite.mCache.push(artInfo, man)
220+
suite.Assert().NoError(err)
221+
}
222+
223+
func (suite *CacheTestSuite) TestManifestCache_push_fails() {
224+
defer suite.local.AssertExpectations(suite.T())
225+
226+
manifest := ociManifest
227+
man, desc, err := distribution.UnmarshalManifest(v1.MediaTypeImageManifest, []byte(manifest))
228+
suite.Require().NoError(err)
229+
230+
repo := "library/hello-world"
231+
232+
artInfo := lib.ArtifactInfo{
233+
Repository: repo,
234+
Digest: string(desc.Digest),
235+
Tag: "latest",
236+
}
237+
238+
digestErr := fmt.Errorf("error during manifest push referencing digest")
239+
tagErr := fmt.Errorf("error during manifest push referencing tag")
240+
suite.local.On("PushManifest", artInfo.Repository, artInfo.Digest, man).Once().Return(digestErr)
241+
suite.local.On("PushManifest", artInfo.Repository, artInfo.Tag, man).Once().Return(tagErr)
242+
243+
err = suite.mCache.push(artInfo, man)
244+
suite.Assert().Error(err)
245+
wrappedErr, isWrappedErr := err.(interface{ Unwrap() []error })
246+
suite.Assert().True(isWrappedErr)
247+
errs := wrappedErr.Unwrap()
248+
suite.Assert().Len(errs, 2)
249+
suite.Assert().Contains(errs, digestErr)
250+
suite.Assert().Contains(errs, tagErr)
251+
}
252+
154253
func TestCacheTestSuite(t *testing.T) {
155254
suite.Run(t, &CacheTestSuite{})
156255
}

0 commit comments

Comments
 (0)