forked from goharbor/harbor
/
default.go
135 lines (123 loc) · 4.51 KB
/
default.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright Project Harbor 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 processor
import (
"context"
"encoding/json"
"regexp"
"strings"
"github.com/docker/distribution/manifest/schema2"
// annotation parsers will be registered
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/goharbor/harbor/src/controller/artifact/annotation"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/registry"
)
const (
// ArtifactTypeUnknown defines the type for the unknown artifacts
ArtifactTypeUnknown = "UNKNOWN"
)
var (
// DefaultProcessor is to process artifact which has no specific processor
DefaultProcessor = &defaultProcessor{regCli: registry.Cli}
artifactTypeRegExp = regexp.MustCompile(`^application/vnd\.[^.]*\.(.*)\.config\.[^.]*\+json$`)
)
// the default processor to process artifact
type defaultProcessor struct {
regCli registry.Client
}
func (d *defaultProcessor) GetArtifactType(_ context.Context, artifact *artifact.Artifact) string {
// try to parse the type from the media type
strs := artifactTypeRegExp.FindStringSubmatch(artifact.MediaType)
if len(strs) == 2 {
return strings.ToUpper(strs[1])
}
// can not get the artifact type from the media type, return unknown
return ArtifactTypeUnknown
}
func (d *defaultProcessor) ListAdditionTypes(_ context.Context, _ *artifact.Artifact) []string {
return nil
}
// The default processor will process user-defined artifact.
// AbstractMetadata will abstract data in a specific way.
// Annotation keys in artifact annotation will decide which content will be processed in artifact.
// Here is a manifest example:
//
// {
// "schemaVersion": 2,
// "config": {
// "mediaType": "application/vnd.caicloud.model.config.v1alpha1+json",
// "digest": "sha256:be948daf0e22f264ea70b713ea0db35050ae659c185706aa2fad74834455fe8c",
// "size": 187,
// "annotations": {
// "io.goharbor.artifact.v1alpha1.skip-list": "metrics,git"
// }
// },
// "layers": [
// {
// "mediaType": "image/png",
// "digest": "sha256:d923b93eadde0af5c639a972710a4d919066aba5d0dfbf4b9385099f70272da0",
// "size": 166015,
// "annotations": {
// "io.goharbor.artifact.v1alpha1.icon": ""
// }
// },
// {
// "mediaType": "application/tar+gzip",
// "digest": "sha256:d923b93eadde0af5c639a972710a4d919066aba5d0dfbf4b9385099f70272da0",
// "size": 166015
// }
// ]
// }
func (d *defaultProcessor) AbstractMetadata(ctx context.Context, artifact *artifact.Artifact, manifest []byte) error {
if artifact.ManifestMediaType != v1.MediaTypeImageManifest && artifact.ManifestMediaType != schema2.MediaTypeManifest {
return nil
}
// get manifest
mani := &v1.Manifest{}
if err := json.Unmarshal(manifest, mani); err != nil {
return err
}
// get config layer
_, blob, err := d.regCli.PullBlob(artifact.RepositoryName, mani.Config.Digest.String())
if err != nil {
return err
}
defer blob.Close()
// parse metadata from config layer
metadata := map[string]interface{}{}
// Some artifact may not have empty config layer.
if mani.Config.Size != 0 {
if err := json.NewDecoder(blob).Decode(&metadata); err != nil {
return err
}
}
// Populate all metadata into the ExtraAttrs first.
artifact.ExtraAttrs = metadata
annotationParser := annotation.NewParser()
err = annotationParser.Parse(ctx, artifact, manifest)
if err != nil {
log.Errorf("the annotation parser parse annotation for artifact error: %v", err)
}
return nil
}
func (d *defaultProcessor) AbstractAddition(_ context.Context, artifact *artifact.Artifact, _ string) (*Addition, error) {
// Addition not support for user-defined artifact yet.
// It will be support in the future.
// return error directly
return nil, errors.New(nil).WithCode(errors.BadRequestCode).
WithMessage("the processor for artifact %s not found, cannot get the addition", artifact.Type)
}