mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-18 14:47:38 +01:00
Implement the index/manifest list image resolver
The index/manifest list image resolver populates the references of the artifact Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
parent
df551e1310
commit
40d5043d5c
@ -12,15 +12,20 @@ package image
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/docker/distribution/manifest/manifestlist"
|
"github.com/docker/distribution/manifest/manifestlist"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/q"
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rslver := &indexResolver{}
|
rslver := &indexResolver{
|
||||||
|
artMgr: artifact.Mgr,
|
||||||
|
}
|
||||||
if err := resolver.Register(rslver, v1.MediaTypeImageIndex, manifestlist.MediaTypeManifestList); err != nil {
|
if err := resolver.Register(rslver, v1.MediaTypeImageIndex, manifestlist.MediaTypeManifestList); err != nil {
|
||||||
log.Errorf("failed to register resolver for artifact %s: %v", rslver.ArtifactType(), err)
|
log.Errorf("failed to register resolver for artifact %s: %v", rslver.ArtifactType(), err)
|
||||||
return
|
return
|
||||||
@ -29,14 +34,39 @@ func init() {
|
|||||||
|
|
||||||
// indexResolver resolves artifact with OCI index and docker manifest list
|
// indexResolver resolves artifact with OCI index and docker manifest list
|
||||||
type indexResolver struct {
|
type indexResolver struct {
|
||||||
|
artMgr artifact.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *indexResolver) ArtifactType() string {
|
func (i *indexResolver) ArtifactType() string {
|
||||||
return ArtifactTypeImage
|
return ArtifactTypeImage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *indexResolver) Resolve(ctx context.Context, manifest []byte, artifact *artifact.Artifact) error {
|
func (i *indexResolver) Resolve(ctx context.Context, manifest []byte, art *artifact.Artifact) error {
|
||||||
// TODO implement
|
index := &v1.Index{}
|
||||||
// how to make sure the artifact referenced by the index has already been saved in database
|
if err := json.Unmarshal(manifest, index); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// populate the referenced artifacts
|
||||||
|
for _, mani := range index.Manifests {
|
||||||
|
digest := mani.Digest.String()
|
||||||
|
_, arts, err := i.artMgr.List(ctx, &q.Query{
|
||||||
|
Keywords: map[string]interface{}{
|
||||||
|
"RepositoryID": art.RepositoryID,
|
||||||
|
"Digest": digest,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// make sure the child artifact exist
|
||||||
|
if len(arts) == 0 {
|
||||||
|
return fmt.Errorf("the referenced artifact with digest %s not found under repository %d",
|
||||||
|
digest, art.RepositoryID)
|
||||||
|
}
|
||||||
|
art.References = append(art.References, &artifact.Reference{
|
||||||
|
ChildID: arts[0].ID,
|
||||||
|
Platform: mani.Platform,
|
||||||
|
})
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
137
src/api/artifact/abstractor/resolver/image/index_test.go
Normal file
137
src/api/artifact/abstractor/resolver/image/index_test.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// 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 image
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
|
htesting "github.com/goharbor/harbor/src/testing"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type indexResolverTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
resolver *indexResolver
|
||||||
|
artMgr *htesting.FakeArtifactManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *indexResolverTestSuite) SetupTest() {
|
||||||
|
i.artMgr = &htesting.FakeArtifactManager{}
|
||||||
|
i.resolver = &indexResolver{
|
||||||
|
artMgr: i.artMgr,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *indexResolverTestSuite) TestArtifactType() {
|
||||||
|
i.Assert().Equal(ArtifactTypeImage, i.resolver.ArtifactType())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *indexResolverTestSuite) TestResolve() {
|
||||||
|
manifest := `{
|
||||||
|
"manifests": [
|
||||||
|
{
|
||||||
|
"digest": "sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a",
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
|
"platform": {
|
||||||
|
"architecture": "amd64",
|
||||||
|
"os": "linux"
|
||||||
|
},
|
||||||
|
"size": 524
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"digest": "sha256:e5785cb0c62cebbed4965129bae371f0589cadd6d84798fb58c2c5f9e237efd9",
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
|
"platform": {
|
||||||
|
"architecture": "arm",
|
||||||
|
"os": "linux",
|
||||||
|
"variant": "v5"
|
||||||
|
},
|
||||||
|
"size": 525
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"digest": "sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1",
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
|
"platform": {
|
||||||
|
"architecture": "arm",
|
||||||
|
"os": "linux",
|
||||||
|
"variant": "v7"
|
||||||
|
},
|
||||||
|
"size": 525
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"digest": "sha256:963612c5503f3f1674f315c67089dee577d8cc6afc18565e0b4183ae355fb343",
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
|
"platform": {
|
||||||
|
"architecture": "arm64",
|
||||||
|
"os": "linux",
|
||||||
|
"variant": "v8"
|
||||||
|
},
|
||||||
|
"size": 525
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"digest": "sha256:85dc5fbe16214366748ebe9d7cc73bc42d61d19d61fe05f01e317d278c2287ed",
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
|
"platform": {
|
||||||
|
"architecture": "386",
|
||||||
|
"os": "linux"
|
||||||
|
},
|
||||||
|
"size": 527
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"digest": "sha256:8aaea2a718a29334caeaf225716284ce29dc17418edba98dbe6dafea5afcda16",
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
|
"platform": {
|
||||||
|
"architecture": "ppc64le",
|
||||||
|
"os": "linux"
|
||||||
|
},
|
||||||
|
"size": 525
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"digest": "sha256:577ad4331d4fac91807308da99ecc107dcc6b2254bc4c7166325fd01113bea2a",
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
|
"platform": {
|
||||||
|
"architecture": "s390x",
|
||||||
|
"os": "linux"
|
||||||
|
},
|
||||||
|
"size": 525
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"digest": "sha256:351e40a9ab7ca6818dfbf9c967d1dd15599438edc41189e3d4d87eeffba5b8bf",
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
|
"platform": {
|
||||||
|
"architecture": "amd64",
|
||||||
|
"os": "windows",
|
||||||
|
"os.version": "10.0.17763.914"
|
||||||
|
},
|
||||||
|
"size": 1124
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
|
||||||
|
"schemaVersion": 2
|
||||||
|
}`
|
||||||
|
art := &artifact.Artifact{}
|
||||||
|
i.artMgr.On("List").Return(1, []*artifact.Artifact{
|
||||||
|
{
|
||||||
|
ID: 1,
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
err := i.resolver.Resolve(nil, []byte(manifest), art)
|
||||||
|
i.Require().Nil(err)
|
||||||
|
i.artMgr.AssertExpectations(i.T())
|
||||||
|
i.Assert().Len(art.References, 8)
|
||||||
|
i.Assert().Equal(int64(1), art.References[0].ChildID)
|
||||||
|
i.Assert().Equal("amd64", art.References[0].Platform.Architecture)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIndexResolverTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &indexResolverTestSuite{})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user