mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-24 03:05:39 +01:00
Merge pull request #11111 from ywk253100/200317_clean_todo
Clean up some TODO items
This commit is contained in:
commit
f02c5570a7
@ -22,8 +22,8 @@ import (
|
|||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/manifest/schema2"
|
"github.com/docker/distribution/manifest/schema2"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor"
|
"github.com/goharbor/harbor/src/api/artifact/processor"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/blob"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/registry"
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,19 +36,23 @@ type Abstractor interface {
|
|||||||
// NewAbstractor creates a new abstractor
|
// NewAbstractor creates a new abstractor
|
||||||
func NewAbstractor() Abstractor {
|
func NewAbstractor() Abstractor {
|
||||||
return &abstractor{
|
return &abstractor{
|
||||||
artMgr: artifact.Mgr,
|
artMgr: artifact.Mgr,
|
||||||
blobFetcher: blob.Fcher,
|
regCli: registry.Cli,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type abstractor struct {
|
type abstractor struct {
|
||||||
artMgr artifact.Manager
|
artMgr artifact.Manager
|
||||||
blobFetcher blob.Fetcher
|
regCli registry.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Artifact) error {
|
func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Artifact) error {
|
||||||
// read manifest content
|
// read manifest content
|
||||||
manifestMediaType, content, err := a.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
|
manifest, _, err := a.regCli.PullManifest(artifact.RepositoryName, artifact.Digest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
manifestMediaType, content, err := manifest.Payload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,13 @@
|
|||||||
package artifact
|
package artifact
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/manifest/schema2"
|
"github.com/docker/distribution/manifest/schema2"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor"
|
"github.com/goharbor/harbor/src/api/artifact/processor"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/processor/blob"
|
|
||||||
tart "github.com/goharbor/harbor/src/testing/pkg/artifact"
|
tart "github.com/goharbor/harbor/src/testing/pkg/artifact"
|
||||||
|
"github.com/goharbor/harbor/src/testing/pkg/registry"
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"testing"
|
"testing"
|
||||||
@ -28,48 +29,126 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
v1Manifest = `{
|
v1Manifest = `{
|
||||||
"name": "hello-world",
|
"schemaVersion": 1,
|
||||||
"tag": "latest",
|
"name": "library/node",
|
||||||
"architecture": "amd64",
|
"tag": "5.5-onbuild",
|
||||||
"fsLayers": [
|
"architecture": "amd64",
|
||||||
{
|
"fsLayers": [
|
||||||
"blobSum": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
|
{
|
||||||
},
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
{
|
|
||||||
"blobSum": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blobSum": "sha256:cc8567d70002e957612902a8e985ea129d831ebe04057d88fb644857caa45d11"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blobSum": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"history": [
|
|
||||||
{
|
|
||||||
"v1Compatibility": "{\"id\":\"e45a5af57b00862e5ef5782a9925979a02ba2b12dff832fd0991335f4a11e5c5\",\"parent\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"created\":\"2014-12-31T22:57:59.178729048Z\",\"container\":\"27b45f8fb11795b52e9605b686159729b0d9ca92f76d40fb4f05a62e19c46b4f\",\"container_config\":{\"Hostname\":\"8ce6509d66e2\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [/hello]\"],\"Image\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":[],\"SecurityOpt\":null,\"Labels\":null},\"docker_version\":\"1.4.1\",\"config\":{\"Hostname\":\"8ce6509d66e2\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/hello\"],\"Image\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":[],\"SecurityOpt\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":0}\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"v1Compatibility": "{\"id\":\"e45a5af57b00862e5ef5782a9925979a02ba2b12dff832fd0991335f4a11e5c5\",\"parent\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"created\":\"2014-12-31T22:57:59.178729048Z\",\"container\":\"27b45f8fb11795b52e9605b686159729b0d9ca92f76d40fb4f05a62e19c46b4f\",\"container_config\":{\"Hostname\":\"8ce6509d66e2\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [/hello]\"],\"Image\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":[],\"SecurityOpt\":null,\"Labels\":null},\"docker_version\":\"1.4.1\",\"config\":{\"Hostname\":\"8ce6509d66e2\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/hello\"],\"Image\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":[],\"SecurityOpt\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":0}\n"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"schemaVersion": 1,
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"header": {
|
|
||||||
"jwk": {
|
|
||||||
"crv": "P-256",
|
|
||||||
"kid": "OD6I:6DRK:JXEJ:KBM4:255X:NSAA:MUSF:E4VM:ZI6W:CUN2:L4Z6:LSF4",
|
|
||||||
"kty": "EC",
|
|
||||||
"x": "3gAwX48IQ5oaYQAYSxor6rYYc_6yjuLCjtQ9LUakg4A",
|
|
||||||
"y": "t72ge6kIA1XOjqjVoEOiPPAURltJFBMGDSQvEGVB010"
|
|
||||||
},
|
|
||||||
"alg": "ES256"
|
|
||||||
},
|
},
|
||||||
"signature": "XREm0L8WNn27Ga_iE_vRnTxVMhhYY0Zst_FfkKopg6gWSoTOZTuW4rK0fg_IqnKkEKlbD83tD46LKEGi5aIVFg",
|
{
|
||||||
"protected": "eyJmb3JtYXRMZW5ndGgiOjY2MjgsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS0wNC0wOFQxODo1Mjo1OVoifQ"
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:e2f0af7be4d7ec1946e55d4edddf90f768fd622573b8f1f0a19fa3a087b11936"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:bb0313a4938416446d43fb6fc25c73d4b495575ae0b537ad2ffa0bb081a99916"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:9e9f27c613944beb01ac418fef42a04eb021787a0eef0126b2c73604a57a1384"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:7a0c192d4d2536499ef0c65fa1c60e27ad39b4c4dcb9c703114bb8dc67f8fa5c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:6ecee6444751349ab3731ee4e10f40b93e98af06a70349ca66962b2c80c5cce2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:9269ba3950bb316abe52dc7010b0758b760e887a0d41af177162a55b2722bab7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:03e1855d4f316edea9545408dcac38be93e9ea6aba6e85610edf76db7ccbbfa7"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"1520dbfa834708e58189bd7ad3ddfe5251fbdab020d274e2f2934b193fedce3e\",\"parent\":\"892e1bee0938dd0f1e6cbe4fda1f9d8efb8529c1c7a6469302b2a616541d5c74\",\"created\":\"2016-01-26T16:54:31.506284103Z\",\"container\":\"57db0fd5498375241dfce628a92a28df825f6c6a185119032760f79802477074\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [\\\"npm\\\" \\\"start\\\"]\"],\"Image\":\"892e1bee0938dd0f1e6cbe4fda1f9d8efb8529c1c7a6469302b2a616541d5c74\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[\"COPY package.json /usr/src/app/\",\"RUN npm install\",\"COPY . /usr/src/app\"],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"npm\",\"start\"],\"Image\":\"892e1bee0938dd0f1e6cbe4fda1f9d8efb8529c1c7a6469302b2a616541d5c74\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[\"COPY package.json /usr/src/app/\",\"RUN npm install\",\"COPY . /usr/src/app\"],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"892e1bee0938dd0f1e6cbe4fda1f9d8efb8529c1c7a6469302b2a616541d5c74\",\"parent\":\"c138a9cd4a0adb6c81597e39bcd0dba2d2c181b2ca9a1a6c521cfbd159d90d2a\",\"created\":\"2016-01-26T16:54:30.676634208Z\",\"container\":\"772e639526dff6564ea3922abbc05d63604be9fd1f068ab53684df7a949067be\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ONBUILD COPY . /usr/src/app\"],\"Image\":\"c138a9cd4a0adb6c81597e39bcd0dba2d2c181b2ca9a1a6c521cfbd159d90d2a\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[\"COPY package.json /usr/src/app/\",\"RUN npm install\",\"COPY . /usr/src/app\"],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"node\"],\"Image\":\"c138a9cd4a0adb6c81597e39bcd0dba2d2c181b2ca9a1a6c521cfbd159d90d2a\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[\"COPY package.json /usr/src/app/\",\"RUN npm install\",\"COPY . /usr/src/app\"],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"c138a9cd4a0adb6c81597e39bcd0dba2d2c181b2ca9a1a6c521cfbd159d90d2a\",\"parent\":\"3484e461ee7551398ff2a5fe7d29a7d8f7c13830f0f7629bd6e0f4d7853f3686\",\"created\":\"2016-01-26T16:54:30.007571536Z\",\"container\":\"2b3d627f133121fb0bdd6e656eb4efa4444a8af832760c59d7942b4b59e3ea18\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ONBUILD RUN npm install\"],\"Image\":\"3484e461ee7551398ff2a5fe7d29a7d8f7c13830f0f7629bd6e0f4d7853f3686\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[\"COPY package.json /usr/src/app/\",\"RUN npm install\"],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"node\"],\"Image\":\"3484e461ee7551398ff2a5fe7d29a7d8f7c13830f0f7629bd6e0f4d7853f3686\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[\"COPY package.json /usr/src/app/\",\"RUN npm install\"],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"3484e461ee7551398ff2a5fe7d29a7d8f7c13830f0f7629bd6e0f4d7853f3686\",\"parent\":\"f8858c27980847a58f59954e09a2a9588ca56f878f8a9d9e9ca7f908a0d4424a\",\"created\":\"2016-01-26T16:54:29.347805328Z\",\"container\":\"c11f79f8aa2a23230f9d44618e5a50230f30a585cfc81cc089ce4848ef1ea97b\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ONBUILD COPY package.json /usr/src/app/\"],\"Image\":\"f8858c27980847a58f59954e09a2a9588ca56f878f8a9d9e9ca7f908a0d4424a\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[\"COPY package.json /usr/src/app/\"],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"node\"],\"Image\":\"f8858c27980847a58f59954e09a2a9588ca56f878f8a9d9e9ca7f908a0d4424a\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[\"COPY package.json /usr/src/app/\"],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"f8858c27980847a58f59954e09a2a9588ca56f878f8a9d9e9ca7f908a0d4424a\",\"parent\":\"f64ab7978e6acb948555df37760590f64ea93ad1d2c23fce5a5658266d24d432\",\"created\":\"2016-01-26T16:54:28.738290402Z\",\"container\":\"a408ee4aa153f75028302c2459f75e96f20da4b95f4cce7c50252f617c4fc215\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) WORKDIR /usr/src/app\"],\"Image\":\"f64ab7978e6acb948555df37760590f64ea93ad1d2c23fce5a5658266d24d432\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"node\"],\"Image\":\"f64ab7978e6acb948555df37760590f64ea93ad1d2c23fce5a5658266d24d432\",\"Volumes\":null,\"WorkingDir\":\"/usr/src/app\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"f64ab7978e6acb948555df37760590f64ea93ad1d2c23fce5a5658266d24d432\",\"parent\":\"5f8d821c760f574dd96974b4d70bc442f79b9f56ffe23530d2523eef026b152f\",\"created\":\"2016-01-26T16:54:28.066325756Z\",\"container\":\"ec647c177e1391cfa1cd60fa0a58147af0cb4b0b932a4c42b0932cf04444d76c\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"mkdir -p /usr/src/app\"],\"Image\":\"5f8d821c760f574dd96974b4d70bc442f79b9f56ffe23530d2523eef026b152f\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"node\"],\"Image\":\"5f8d821c760f574dd96974b4d70bc442f79b9f56ffe23530d2523eef026b152f\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"5f8d821c760f574dd96974b4d70bc442f79b9f56ffe23530d2523eef026b152f\",\"parent\":\"ebcf22a55440806b2cf690333dc39f6321deda73a34a790468f3ef58e459eeb6\",\"created\":\"2016-01-26T16:52:50.89027915Z\",\"container\":\"db127a54c3e12c478d144a0e480ee7f4ac3909d1440e9372bf54be82507ec5d7\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [\\\"node\\\"]\"],\"Image\":\"ebcf22a55440806b2cf690333dc39f6321deda73a34a790468f3ef58e459eeb6\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"node\"],\"Image\":\"ebcf22a55440806b2cf690333dc39f6321deda73a34a790468f3ef58e459eeb6\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"ebcf22a55440806b2cf690333dc39f6321deda73a34a790468f3ef58e459eeb6\",\"parent\":\"20ed370cdb6e6e36c94a673270155b7edc669e583f870e48833125f828e89e65\",\"created\":\"2016-01-26T16:52:45.83954478Z\",\"container\":\"5cbb1dc61fe39c8f13e41bb72956f8764c828f79c18d5dfcc6b1ff111e88b997\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"curl -SLO \\\"https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz\\\" \\u0026\\u0026 curl -SLO \\\"https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc\\\" \\u0026\\u0026 gpg --verify SHASUMS256.txt.asc \\u0026\\u0026 grep \\\" node-v$NODE_VERSION-linux-x64.tar.gz\\\\$\\\" SHASUMS256.txt.asc | sha256sum -c - \\u0026\\u0026 tar -xzf \\\"node-v$NODE_VERSION-linux-x64.tar.gz\\\" -C /usr/local --strip-components=1 \\u0026\\u0026 rm \\\"node-v$NODE_VERSION-linux-x64.tar.gz\\\" SHASUMS256.txt.asc\"],\"Image\":\"20ed370cdb6e6e36c94a673270155b7edc669e583f870e48833125f828e89e65\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/bash\"],\"Image\":\"20ed370cdb6e6e36c94a673270155b7edc669e583f870e48833125f828e89e65\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":36385291}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"20ed370cdb6e6e36c94a673270155b7edc669e583f870e48833125f828e89e65\",\"parent\":\"8ab6f3fcbdb58860b302cb53d3c090d1e4a56cc5a4ac548724be143f292bbd08\",\"created\":\"2016-01-26T16:52:38.484938978Z\",\"container\":\"db88a6dff38e4b3fc8798f5fbe7cff5a9c3a1fa2627fcb7601e627a18ef1359d\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ENV NODE_VERSION=5.5.0\"],\"Image\":\"8ab6f3fcbdb58860b302cb53d3c090d1e4a56cc5a4ac548724be143f292bbd08\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\",\"NODE_VERSION=5.5.0\"],\"Cmd\":[\"/bin/bash\"],\"Image\":\"8ab6f3fcbdb58860b302cb53d3c090d1e4a56cc5a4ac548724be143f292bbd08\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"8ab6f3fcbdb58860b302cb53d3c090d1e4a56cc5a4ac548724be143f292bbd08\",\"parent\":\"ddfb2360ce1e908d5ecb4b678ee10686ba28a4fdcc68d70177d8fbafcaf2da24\",\"created\":\"2016-01-26T16:44:56.182612087Z\",\"container\":\"c510a06b1df9a9989f02337b1c0cbe0c549381e8d6d2f8f6e660328944c0186e\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ENV NPM_CONFIG_LOGLEVEL=info\"],\"Image\":\"ddfb2360ce1e908d5ecb4b678ee10686ba28a4fdcc68d70177d8fbafcaf2da24\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\"NPM_CONFIG_LOGLEVEL=info\"],\"Cmd\":[\"/bin/bash\"],\"Image\":\"ddfb2360ce1e908d5ecb4b678ee10686ba28a4fdcc68d70177d8fbafcaf2da24\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"ddfb2360ce1e908d5ecb4b678ee10686ba28a4fdcc68d70177d8fbafcaf2da24\",\"parent\":\"9536cbaf1242bbc772d382c828ad4c8d317fcd63ef9cde05f9cb4cd4b6871236\",\"created\":\"2016-01-26T16:38:21.781529683Z\",\"container\":\"f2ef38095c6c3a99e64a14d3d433f0a7ed7ecef2264afe40ccbeb93b38bc77d9\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"set -ex \\u0026\\u0026 for key in 9554F04D7259F04124DE6B476D5A82AC7E37093B 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 0034A06D9D9B0064CE8ADF6BF1747F4AD2306D93 FD3A5288F042B6850C66B31F09FE44734EB7990E 71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 DD8F2338BAE7501E3DD5AC78C273792F7D83545D B9AE9905FFD7803F25714661B63B535A4C206CA9 C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 ; do gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \\\"$key\\\"; done\"],\"Image\":\"9536cbaf1242bbc772d382c828ad4c8d317fcd63ef9cde05f9cb4cd4b6871236\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/bash\"],\"Image\":\"9536cbaf1242bbc772d382c828ad4c8d317fcd63ef9cde05f9cb4cd4b6871236\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":51753}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"9536cbaf1242bbc772d382c828ad4c8d317fcd63ef9cde05f9cb4cd4b6871236\",\"parent\":\"0288ae931294ce04f5d69c60146faca7d9be8de4004421d650f4227fa60bd92b\",\"created\":\"2016-01-25T22:31:08.823570982Z\",\"container\":\"528b705b36c3a1ae37343eec7824283170b0bffe8b40f16f830eab723ac2f08d\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"apt-get update \\u0026\\u0026 apt-get install -y --no-install-recommends \\t\\tautoconf \\t\\tautomake \\t\\tbzip2 \\t\\tfile \\t\\tg++ \\t\\tgcc \\t\\timagemagick \\t\\tlibbz2-dev \\t\\tlibc6-dev \\t\\tlibcurl4-openssl-dev \\t\\tlibevent-dev \\t\\tlibffi-dev \\t\\tlibgeoip-dev \\t\\tlibglib2.0-dev \\t\\tlibjpeg-dev \\t\\tliblzma-dev \\t\\tlibmagickcore-dev \\t\\tlibmagickwand-dev \\t\\tlibmysqlclient-dev \\t\\tlibncurses-dev \\t\\tlibpng-dev \\t\\tlibpq-dev \\t\\tlibreadline-dev \\t\\tlibsqlite3-dev \\t\\tlibssl-dev \\t\\tlibtool \\t\\tlibwebp-dev \\t\\tlibxml2-dev \\t\\tlibxslt-dev \\t\\tlibyaml-dev \\t\\tmake \\t\\tpatch \\t\\txz-utils \\t\\tzlib1g-dev \\t\\u0026\\u0026 rm -rf /var/lib/apt/lists/*\"],\"Image\":\"0288ae931294ce04f5d69c60146faca7d9be8de4004421d650f4227fa60bd92b\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/bash\"],\"Image\":\"0288ae931294ce04f5d69c60146faca7d9be8de4004421d650f4227fa60bd92b\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":314656819}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"0288ae931294ce04f5d69c60146faca7d9be8de4004421d650f4227fa60bd92b\",\"parent\":\"9287fae7a16e8788603ae069270aa825457065062247f4c04d4983f00eba37a6\",\"created\":\"2016-01-25T22:29:12.503492968Z\",\"container\":\"a0533596d15ff539859472684f7e700042f357d02fa0c1fb6c5d8a1feac6c574\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"apt-get update \\u0026\\u0026 apt-get install -y --no-install-recommends \\t\\tbzr \\t\\tgit \\t\\tmercurial \\t\\topenssh-client \\t\\tsubversion \\t\\t\\t\\tprocps \\t\\u0026\\u0026 rm -rf /var/lib/apt/lists/*\"],\"Image\":\"9287fae7a16e8788603ae069270aa825457065062247f4c04d4983f00eba37a6\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/bash\"],\"Image\":\"9287fae7a16e8788603ae069270aa825457065062247f4c04d4983f00eba37a6\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":122576525}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"9287fae7a16e8788603ae069270aa825457065062247f4c04d4983f00eba37a6\",\"parent\":\"5eb1402f041415f4d72ec331c9388e4981420dfe88ef4e9bdf904d4687e4de09\",\"created\":\"2016-01-25T22:28:10.88750042Z\",\"container\":\"ce5ccec57f456f36a78b32dad3a696a215ff0201270d47ee1c2f64a52508297a\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"apt-get update \\u0026\\u0026 apt-get install -y --no-install-recommends \\t\\tca-certificates \\t\\tcurl \\t\\twget \\t\\u0026\\u0026 rm -rf /var/lib/apt/lists/*\"],\"Image\":\"5eb1402f041415f4d72ec331c9388e4981420dfe88ef4e9bdf904d4687e4de09\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/bash\"],\"Image\":\"5eb1402f041415f4d72ec331c9388e4981420dfe88ef4e9bdf904d4687e4de09\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":44300304}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"5eb1402f041415f4d72ec331c9388e4981420dfe88ef4e9bdf904d4687e4de09\",\"parent\":\"77e39ee8211729e81d1f83f0c64fdef97979b930a97ddc8194b8ea46d49f7b50\",\"created\":\"2016-01-25T22:24:37.914712562Z\",\"container\":\"c59024072143b04b79ac341c51571fc698636e01c13b49c523309c84af4b70fe\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [\\\"/bin/bash\\\"]\"],\"Image\":\"77e39ee8211729e81d1f83f0c64fdef97979b930a97ddc8194b8ea46d49f7b50\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/bash\"],\"Image\":\"77e39ee8211729e81d1f83f0c64fdef97979b930a97ddc8194b8ea46d49f7b50\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"77e39ee8211729e81d1f83f0c64fdef97979b930a97ddc8194b8ea46d49f7b50\",\"created\":\"2016-01-25T22:24:35.279128653Z\",\"container\":\"e06f5a03fe1f6755f98fb354799db823a95e6c141ae40a2cb7ad7a6b09d41208\",\"container_config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ADD file:e5a3d20748c5d3dd5fa11542dfa4ef8b72a0bb78ce09f6dae30eff5d045c67aa in /\"],\"Image\":\"\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"e06f5a03fe1f\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":125082947}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"header": {
|
||||||
|
"jwk": {
|
||||||
|
"crv": "P-256",
|
||||||
|
"kid": "KG7S:QIPL:FTS3:YAKZ:AADA:4GML:ITLH:7APP:O4F7:2NBA:A4IN:CWVF",
|
||||||
|
"kty": "EC",
|
||||||
|
"x": "PUiT1kV7Xf-U8M54gpCzvPc5mDUX9BjvizdBgy3oTsI",
|
||||||
|
"y": "BAgeQchl9QibzPP2Qp_-gJMWr682QVWoHy52hLRHZ04"
|
||||||
|
},
|
||||||
|
"alg": "ES256"
|
||||||
|
},
|
||||||
|
"signature": "mfUOI0pPzkdceAKAFRMkrQVgeE9X7if43LEtfs5XvdyxO7lCG0fiVxmdi-KGaQu4lRsIfRNq6m5agNTm8u5DrA",
|
||||||
|
"protected": "eyJmb3JtYXRMZW5ndGgiOjI3NTE4LCJmb3JtYXRUYWlsIjoiQ24wIiwidGltZSI6IjIwMjAtMDMtMTdUMTA6NTk6MDhaIn0"
|
||||||
|
}
|
||||||
|
]
|
||||||
}`
|
}`
|
||||||
v2Manifest = `{
|
v2Manifest = `{
|
||||||
"schemaVersion": 2,
|
"schemaVersion": 2,
|
||||||
@ -122,16 +201,16 @@ var (
|
|||||||
type abstractorTestSuite struct {
|
type abstractorTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
argMgr *tart.FakeManager
|
argMgr *tart.FakeManager
|
||||||
fetcher *blob.FakeFetcher
|
regCli *registry.FakeClient
|
||||||
abstractor *abstractor
|
abstractor *abstractor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *abstractorTestSuite) SetupTest() {
|
func (a *abstractorTestSuite) SetupTest() {
|
||||||
a.fetcher = &blob.FakeFetcher{}
|
a.regCli = ®istry.FakeClient{}
|
||||||
a.argMgr = &tart.FakeManager{}
|
a.argMgr = &tart.FakeManager{}
|
||||||
a.abstractor = &abstractor{
|
a.abstractor = &abstractor{
|
||||||
artMgr: a.argMgr,
|
artMgr: a.argMgr,
|
||||||
blobFetcher: a.fetcher,
|
regCli: a.regCli,
|
||||||
}
|
}
|
||||||
// clear all registered processors
|
// clear all registered processors
|
||||||
processor.Registry = map[string]processor.Processor{}
|
processor.Registry = map[string]processor.Processor{}
|
||||||
@ -139,11 +218,13 @@ func (a *abstractorTestSuite) SetupTest() {
|
|||||||
|
|
||||||
// docker manifest v1
|
// docker manifest v1
|
||||||
func (a *abstractorTestSuite) TestAbstractMetadataOfV1Manifest() {
|
func (a *abstractorTestSuite) TestAbstractMetadataOfV1Manifest() {
|
||||||
a.fetcher.On("FetchManifest").Return(schema1.MediaTypeSignedManifest, []byte(v1Manifest), nil)
|
manifest, _, err := distribution.UnmarshalManifest(schema1.MediaTypeSignedManifest, []byte(v1Manifest))
|
||||||
|
a.Require().Nil(err)
|
||||||
|
a.regCli.On("PullManifest").Return(manifest, "", nil)
|
||||||
artifact := &artifact.Artifact{
|
artifact := &artifact.Artifact{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
}
|
}
|
||||||
err := a.abstractor.AbstractMetadata(nil, artifact)
|
err = a.abstractor.AbstractMetadata(nil, artifact)
|
||||||
a.Require().Nil(err)
|
a.Require().Nil(err)
|
||||||
a.Assert().Equal(int64(1), artifact.ID)
|
a.Assert().Equal(int64(1), artifact.ID)
|
||||||
a.Assert().Equal(schema1.MediaTypeSignedManifest, artifact.ManifestMediaType)
|
a.Assert().Equal(schema1.MediaTypeSignedManifest, artifact.ManifestMediaType)
|
||||||
@ -153,11 +234,13 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfV1Manifest() {
|
|||||||
|
|
||||||
// docker manifest v2
|
// docker manifest v2
|
||||||
func (a *abstractorTestSuite) TestAbstractMetadataOfV2Manifest() {
|
func (a *abstractorTestSuite) TestAbstractMetadataOfV2Manifest() {
|
||||||
a.fetcher.On("FetchManifest").Return(schema2.MediaTypeManifest, []byte(v2Manifest), nil)
|
manifest, _, err := distribution.UnmarshalManifest(schema2.MediaTypeManifest, []byte(v2Manifest))
|
||||||
|
a.Require().Nil(err)
|
||||||
|
a.regCli.On("PullManifest").Return(manifest, "", nil)
|
||||||
artifact := &artifact.Artifact{
|
artifact := &artifact.Artifact{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
}
|
}
|
||||||
err := a.abstractor.AbstractMetadata(nil, artifact)
|
err = a.abstractor.AbstractMetadata(nil, artifact)
|
||||||
a.Require().Nil(err)
|
a.Require().Nil(err)
|
||||||
a.Assert().Equal(int64(1), artifact.ID)
|
a.Assert().Equal(int64(1), artifact.ID)
|
||||||
a.Assert().Equal(schema2.MediaTypeManifest, artifact.ManifestMediaType)
|
a.Assert().Equal(schema2.MediaTypeManifest, artifact.ManifestMediaType)
|
||||||
@ -169,7 +252,9 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfV2Manifest() {
|
|||||||
|
|
||||||
// OCI index
|
// OCI index
|
||||||
func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
|
func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
|
||||||
a.fetcher.On("FetchManifest").Return(v1.MediaTypeImageIndex, []byte(index), nil)
|
manifest, _, err := distribution.UnmarshalManifest(v1.MediaTypeImageIndex, []byte(index))
|
||||||
|
a.Require().Nil(err)
|
||||||
|
a.regCli.On("PullManifest").Return(manifest, "", nil)
|
||||||
a.argMgr.On("GetByDigest").Return(&artifact.Artifact{
|
a.argMgr.On("GetByDigest").Return(&artifact.Artifact{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Size: 10,
|
Size: 10,
|
||||||
@ -177,7 +262,7 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
|
|||||||
artifact := &artifact.Artifact{
|
artifact := &artifact.Artifact{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
}
|
}
|
||||||
err := a.abstractor.AbstractMetadata(nil, artifact)
|
err = a.abstractor.AbstractMetadata(nil, artifact)
|
||||||
a.Require().Nil(err)
|
a.Require().Nil(err)
|
||||||
a.Assert().Equal(int64(1), artifact.ID)
|
a.Assert().Equal(int64(1), artifact.ID)
|
||||||
a.Assert().Equal(v1.MediaTypeImageIndex, artifact.ManifestMediaType)
|
a.Assert().Equal(v1.MediaTypeImageIndex, artifact.ManifestMediaType)
|
||||||
@ -188,9 +273,18 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
|
|||||||
a.Len(artifact.References, 2)
|
a.Len(artifact.References, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OCI index
|
type unknownManifest struct{}
|
||||||
|
|
||||||
|
func (u *unknownManifest) References() []distribution.Descriptor {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (u *unknownManifest) Payload() (mediaType string, payload []byte, err error) {
|
||||||
|
return "unknown-manifest", nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown
|
||||||
func (a *abstractorTestSuite) TestAbstractMetadataOfUnsupported() {
|
func (a *abstractorTestSuite) TestAbstractMetadataOfUnsupported() {
|
||||||
a.fetcher.On("FetchManifest").Return("unsupported-manifest", []byte{}, nil)
|
a.regCli.On("PullManifest").Return(&unknownManifest{}, "", nil)
|
||||||
artifact := &artifact.Artifact{
|
artifact := &artifact.Artifact{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,20 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/api/artifact/processor"
|
"github.com/goharbor/harbor/src/api/artifact/processor"
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewIndexProcessor creates a new base index processor.
|
||||||
|
func NewIndexProcessor() *IndexProcessor {
|
||||||
|
return &IndexProcessor{
|
||||||
|
RegCli: registry.Cli,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IndexProcessor is a base processor to process artifact enveloped by OCI index or docker manifest list
|
// IndexProcessor is a base processor to process artifact enveloped by OCI index or docker manifest list
|
||||||
// Currently, it is just a null implementation
|
// Currently, it is just a null implementation
|
||||||
type IndexProcessor struct {
|
type IndexProcessor struct {
|
||||||
|
RegCli registry.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbstractMetadata abstracts metadata of artifact
|
// AbstractMetadata abstracts metadata of artifact
|
||||||
|
@ -18,9 +18,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor"
|
"github.com/goharbor/harbor/src/api/artifact/processor"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/blob"
|
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/registry"
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,15 +28,15 @@ import (
|
|||||||
// All metadata read from config layer will be populated if specifying no "properties"
|
// All metadata read from config layer will be populated if specifying no "properties"
|
||||||
func NewManifestProcessor(properties ...string) *ManifestProcessor {
|
func NewManifestProcessor(properties ...string) *ManifestProcessor {
|
||||||
return &ManifestProcessor{
|
return &ManifestProcessor{
|
||||||
properties: properties,
|
properties: properties,
|
||||||
BlobFetcher: blob.Fcher,
|
RegCli: registry.Cli,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManifestProcessor is a base processor to process artifact enveloped by OCI manifest or docker v2 manifest
|
// ManifestProcessor is a base processor to process artifact enveloped by OCI manifest or docker v2 manifest
|
||||||
type ManifestProcessor struct {
|
type ManifestProcessor struct {
|
||||||
properties []string
|
properties []string
|
||||||
BlobFetcher blob.Fetcher
|
RegCli registry.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbstractMetadata abstracts metadata of artifact
|
// AbstractMetadata abstracts metadata of artifact
|
||||||
@ -47,13 +47,14 @@ func (m *ManifestProcessor) AbstractMetadata(ctx context.Context, content []byte
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// get config layer
|
// get config layer
|
||||||
layer, err := m.BlobFetcher.FetchLayer(artifact.RepositoryName, manifest.Config.Digest.String())
|
_, blob, err := m.RegCli.PullBlob(artifact.RepositoryName, manifest.Config.Digest.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer blob.Close()
|
||||||
// parse metadata from config layer
|
// parse metadata from config layer
|
||||||
metadata := map[string]interface{}{}
|
metadata := map[string]interface{}{}
|
||||||
if err := json.Unmarshal(layer, &metadata); err != nil {
|
if err := json.NewDecoder(blob).Decode(&metadata); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// if no properties specified, populate all metadata into the ExtraAttrs
|
// if no properties specified, populate all metadata into the ExtraAttrs
|
||||||
|
@ -15,10 +15,13 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"io/ioutil"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/processor/blob"
|
"strings"
|
||||||
"github.com/stretchr/testify/suite"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
|
"github.com/goharbor/harbor/src/testing/pkg/registry"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -119,21 +122,22 @@ const (
|
|||||||
|
|
||||||
type manifestTestSuite struct {
|
type manifestTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
processor *ManifestProcessor
|
processor *ManifestProcessor
|
||||||
blobFetcher *blob.FakeFetcher
|
regCli *registry.FakeClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifestTestSuite) SetupTest() {
|
func (m *manifestTestSuite) SetupTest() {
|
||||||
m.blobFetcher = &blob.FakeFetcher{}
|
m.regCli = ®istry.FakeClient{}
|
||||||
m.processor = &ManifestProcessor{
|
m.processor = &ManifestProcessor{
|
||||||
BlobFetcher: m.blobFetcher,
|
RegCli: m.regCli,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifestTestSuite) TestAbstractMetadata() {
|
func (m *manifestTestSuite) TestAbstractMetadata() {
|
||||||
// abstract all properties
|
// abstract all properties
|
||||||
art := &artifact.Artifact{}
|
art := &artifact.Artifact{}
|
||||||
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
|
||||||
|
m.regCli.On("PullBlob").Return(0, ioutil.NopCloser(strings.NewReader(config)), nil)
|
||||||
m.processor.AbstractMetadata(nil, []byte(manifest), art)
|
m.processor.AbstractMetadata(nil, []byte(manifest), art)
|
||||||
m.Len(art.ExtraAttrs, 9)
|
m.Len(art.ExtraAttrs, 9)
|
||||||
|
|
||||||
@ -143,7 +147,7 @@ func (m *manifestTestSuite) TestAbstractMetadata() {
|
|||||||
// abstract the specified properties
|
// abstract the specified properties
|
||||||
m.processor.properties = []string{"os"}
|
m.processor.properties = []string{"os"}
|
||||||
art = &artifact.Artifact{}
|
art = &artifact.Artifact{}
|
||||||
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
m.regCli.On("PullBlob").Return(0, ioutil.NopCloser(strings.NewReader(config)), nil)
|
||||||
m.processor.AbstractMetadata(nil, []byte(manifest), art)
|
m.processor.AbstractMetadata(nil, []byte(manifest), art)
|
||||||
m.Require().Len(art.ExtraAttrs, 1)
|
m.Require().Len(art.ExtraAttrs, 1)
|
||||||
m.Equal("linux", art.ExtraAttrs["os"])
|
m.Equal("linux", art.ExtraAttrs["os"])
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
// 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 blob
|
|
||||||
|
|
||||||
// TODO add cache
|
|
||||||
// TODO cache content and mediatype
|
|
@ -1,81 +0,0 @@
|
|||||||
// 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 blob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/docker/distribution/manifest/manifestlist"
|
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
|
||||||
"github.com/docker/distribution/manifest/schema2"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/registry"
|
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Fcher is a global blob fetcher instance
|
|
||||||
Fcher = NewFetcher()
|
|
||||||
|
|
||||||
accept = []string{
|
|
||||||
schema1.MediaTypeSignedManifest,
|
|
||||||
schema2.MediaTypeManifest,
|
|
||||||
v1.MediaTypeImageManifest,
|
|
||||||
manifestlist.MediaTypeManifestList,
|
|
||||||
v1.MediaTypeImageIndex,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO use the registry.Client directly? then the Fetcher can be deleted
|
|
||||||
|
|
||||||
// Fetcher fetches the content of blob
|
|
||||||
type Fetcher interface {
|
|
||||||
// FetchManifest the content of manifest under the repository
|
|
||||||
FetchManifest(repository, digest string) (mediaType string, content []byte, err error)
|
|
||||||
// FetchLayer the content of layer under the repository
|
|
||||||
FetchLayer(repository, digest string) (content []byte, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFetcher returns an instance of the default blob fetcher
|
|
||||||
func NewFetcher() Fetcher {
|
|
||||||
return &fetcher{
|
|
||||||
client: registry.Cli,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type fetcher struct {
|
|
||||||
client registry.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fetcher) FetchManifest(repository, digest string) (string, []byte, error) {
|
|
||||||
// TODO read from cache first
|
|
||||||
manifest, _, err := f.client.PullManifest(repository, digest)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
mediaType, payload, err := manifest.Payload()
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
return mediaType, payload, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fetcher) FetchLayer(repository, digest string) ([]byte, error) {
|
|
||||||
// TODO read from cache first
|
|
||||||
_, reader, err := f.client.PullBlob(repository, digest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer reader.Close()
|
|
||||||
return ioutil.ReadAll(reader)
|
|
||||||
}
|
|
@ -17,9 +17,10 @@ package chart
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
ps "github.com/goharbor/harbor/src/api/artifact/processor"
|
ps "github.com/goharbor/harbor/src/api/artifact/processor"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/blob"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
@ -35,13 +36,13 @@ const (
|
|||||||
AdditionTypeReadme = "README.MD"
|
AdditionTypeReadme = "README.MD"
|
||||||
AdditionTypeDependencies = "DEPENDENCIES"
|
AdditionTypeDependencies = "DEPENDENCIES"
|
||||||
|
|
||||||
// TODO import it from helm chart repository
|
// as helm put the media type definition under "internal" package, we cannot
|
||||||
|
// import it, defines it by ourselves
|
||||||
mediaType = "application/vnd.cncf.helm.config.v1+json"
|
mediaType = "application/vnd.cncf.helm.config.v1+json"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
pc := &processor{
|
pc := &processor{
|
||||||
blobFetcher: blob.Fcher,
|
|
||||||
chartOperator: chart.Optr,
|
chartOperator: chart.Optr,
|
||||||
}
|
}
|
||||||
pc.ManifestProcessor = base.NewManifestProcessor()
|
pc.ManifestProcessor = base.NewManifestProcessor()
|
||||||
@ -53,7 +54,6 @@ func init() {
|
|||||||
|
|
||||||
type processor struct {
|
type processor struct {
|
||||||
*base.ManifestProcessor
|
*base.ManifestProcessor
|
||||||
blobFetcher blob.Fetcher
|
|
||||||
chartOperator chart.Operator
|
chartOperator chart.Operator
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,12 +63,16 @@ func (p *processor) AbstractAddition(ctx context.Context, artifact *artifact.Art
|
|||||||
WithMessage("addition %s isn't supported for %s", addition, ArtifactTypeChart)
|
WithMessage("addition %s isn't supported for %s", addition, ArtifactTypeChart)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, content, err := p.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
|
m, _, err := p.RegCli.PullManifest(artifact.RepositoryName, artifact.Digest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, payload, err := m.Payload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
manifest := &v1.Manifest{}
|
manifest := &v1.Manifest{}
|
||||||
if err := json.Unmarshal(content, manifest); err != nil {
|
if err := json.Unmarshal(payload, manifest); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,10 +80,15 @@ func (p *processor) AbstractAddition(ctx context.Context, artifact *artifact.Art
|
|||||||
// chart do have two layers, one is config, we should resolve the other one.
|
// chart do have two layers, one is config, we should resolve the other one.
|
||||||
layerDgst := layer.Digest.String()
|
layerDgst := layer.Digest.String()
|
||||||
if layerDgst != manifest.Config.Digest.String() {
|
if layerDgst != manifest.Config.Digest.String() {
|
||||||
content, err = p.blobFetcher.FetchLayer(artifact.RepositoryName, layerDgst)
|
_, blob, err := p.RegCli.PullBlob(artifact.RepositoryName, layerDgst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
content, err := ioutil.ReadAll(blob)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blob.Close()
|
||||||
chartDetails, err := p.chartOperator.GetDetails(content)
|
chartDetails, err := p.chartOperator.GetDetails(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -15,31 +15,35 @@
|
|||||||
package chart
|
package chart
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/distribution"
|
||||||
|
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
chartserver "github.com/goharbor/harbor/src/pkg/chart"
|
chartserver "github.com/goharbor/harbor/src/pkg/chart"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/processor/blob"
|
|
||||||
"github.com/goharbor/harbor/src/testing/pkg/chart"
|
"github.com/goharbor/harbor/src/testing/pkg/chart"
|
||||||
|
"github.com/goharbor/harbor/src/testing/pkg/registry"
|
||||||
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
helm_chart "helm.sh/helm/v3/pkg/chart"
|
helm_chart "helm.sh/helm/v3/pkg/chart"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type processorTestSuite struct {
|
type processorTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
processor *processor
|
processor *processor
|
||||||
blobFetcher *blob.FakeFetcher
|
regCli *registry.FakeClient
|
||||||
chartOptr *chart.FakeOpertaor
|
chartOptr *chart.FakeOpertaor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *processorTestSuite) SetupTest() {
|
func (p *processorTestSuite) SetupTest() {
|
||||||
p.blobFetcher = &blob.FakeFetcher{}
|
p.regCli = ®istry.FakeClient{}
|
||||||
p.chartOptr = &chart.FakeOpertaor{}
|
p.chartOptr = &chart.FakeOpertaor{}
|
||||||
p.processor = &processor{
|
p.processor = &processor{
|
||||||
blobFetcher: p.blobFetcher,
|
|
||||||
chartOperator: p.chartOptr,
|
chartOperator: p.chartOptr,
|
||||||
}
|
}
|
||||||
|
p.processor.ManifestProcessor = &base.ManifestProcessor{RegCli: p.regCli}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *processorTestSuite) TestAbstractAddition() {
|
func (p *processorTestSuite) TestAbstractAddition() {
|
||||||
@ -98,8 +102,10 @@ func (p *processorTestSuite) TestAbstractAddition() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
artifact := &artifact.Artifact{}
|
artifact := &artifact.Artifact{}
|
||||||
p.blobFetcher.On("FetchManifest").Return("", []byte(chartManifest), nil)
|
manifest, _, err := distribution.UnmarshalManifest(v1.MediaTypeImageManifest, []byte(chartManifest))
|
||||||
p.blobFetcher.On("FetchLayer").Return([]byte(chartYaml), nil)
|
p.Require().Nil(err)
|
||||||
|
p.regCli.On("PullManifest").Return(manifest, "", nil)
|
||||||
|
p.regCli.On("PullBlob").Return(0, ioutil.NopCloser(strings.NewReader(chartYaml)), nil)
|
||||||
p.chartOptr.On("GetDetails").Return(chartDetails, nil)
|
p.chartOptr.On("GetDetails").Return(chartDetails, nil)
|
||||||
|
|
||||||
// values.yaml
|
// values.yaml
|
||||||
|
@ -16,9 +16,9 @@ package cnab
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
ps "github.com/goharbor/harbor/src/api/artifact/processor"
|
ps "github.com/goharbor/harbor/src/api/artifact/processor"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/blob"
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
@ -31,10 +31,9 @@ const (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
pc := &processor{
|
pc := &processor{
|
||||||
blobFetcher: blob.Fcher,
|
|
||||||
manifestProcessor: base.NewManifestProcessor(),
|
manifestProcessor: base.NewManifestProcessor(),
|
||||||
}
|
}
|
||||||
pc.IndexProcessor = &base.IndexProcessor{}
|
pc.IndexProcessor = base.NewIndexProcessor()
|
||||||
if err := ps.Register(pc, mediaType); err != nil {
|
if err := ps.Register(pc, mediaType); err != nil {
|
||||||
log.Errorf("failed to register processor for media type %s: %v", mediaType, err)
|
log.Errorf("failed to register processor for media type %s: %v", mediaType, err)
|
||||||
return
|
return
|
||||||
@ -44,7 +43,6 @@ func init() {
|
|||||||
type processor struct {
|
type processor struct {
|
||||||
*base.IndexProcessor
|
*base.IndexProcessor
|
||||||
manifestProcessor *base.ManifestProcessor
|
manifestProcessor *base.ManifestProcessor
|
||||||
blobFetcher blob.Fetcher
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *processor) AbstractMetadata(ctx context.Context, manifest []byte, art *artifact.Artifact) error {
|
func (p *processor) AbstractMetadata(ctx context.Context, manifest []byte, art *artifact.Artifact) error {
|
||||||
@ -61,13 +59,17 @@ func (p *processor) AbstractMetadata(ctx context.Context, manifest []byte, art *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the manifest that the config layer is referenced by
|
// get the manifest that the config layer is referenced by
|
||||||
_, cfgMani, err := p.blobFetcher.FetchManifest(art.RepositoryName, cfgManiDgt)
|
mani, _, err := p.RegCli.PullManifest(art.RepositoryName, cfgManiDgt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, payload, err := mani.Payload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// abstract the metadata from config layer
|
// abstract the metadata from config layer
|
||||||
return p.manifestProcessor.AbstractMetadata(ctx, cfgMani, art)
|
return p.manifestProcessor.AbstractMetadata(ctx, payload, art)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *processor) GetArtifactType() string {
|
func (p *processor) GetArtifactType() string {
|
||||||
|
@ -15,28 +15,31 @@
|
|||||||
package cnab
|
package cnab
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/processor/blob"
|
"github.com/goharbor/harbor/src/testing/pkg/registry"
|
||||||
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type processorTestSuite struct {
|
type processorTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
processor *processor
|
processor *processor
|
||||||
blobFetcher *blob.FakeFetcher
|
regCli *registry.FakeClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *processorTestSuite) SetupTest() {
|
func (p *processorTestSuite) SetupTest() {
|
||||||
p.blobFetcher = &blob.FakeFetcher{}
|
p.regCli = ®istry.FakeClient{}
|
||||||
p.processor = &processor{
|
p.processor = &processor{
|
||||||
blobFetcher: p.blobFetcher,
|
|
||||||
manifestProcessor: &base.ManifestProcessor{
|
manifestProcessor: &base.ManifestProcessor{
|
||||||
BlobFetcher: p.blobFetcher,
|
RegCli: p.regCli,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
p.processor.IndexProcessor = &base.IndexProcessor{RegCli: p.regCli}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *processorTestSuite) TestAbstractMetadata() {
|
func (p *processorTestSuite) TestAbstractMetadata() {
|
||||||
@ -86,9 +89,11 @@ func (p *processorTestSuite) TestAbstractMetadata() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
p.blobFetcher.On("FetchManifest").Return("", []byte(manifest), nil)
|
mani, _, err := distribution.UnmarshalManifest(v1.MediaTypeImageManifest, []byte(manifest))
|
||||||
p.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
p.Require().Nil(err)
|
||||||
err := p.processor.AbstractMetadata(nil, nil, art)
|
p.regCli.On("PullManifest").Return(mani, "", nil)
|
||||||
|
p.regCli.On("PullBlob").Return(0, ioutil.NopCloser(strings.NewReader(config)), nil)
|
||||||
|
err = p.processor.AbstractMetadata(nil, nil, art)
|
||||||
p.Require().Nil(err)
|
p.Require().Nil(err)
|
||||||
p.Len(art.ExtraAttrs, 7)
|
p.Len(art.ExtraAttrs, 7)
|
||||||
p.Equal("0.1.1", art.ExtraAttrs["version"].(string))
|
p.Equal("0.1.1", art.ExtraAttrs["version"].(string))
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/docker/distribution/manifest/schema2"
|
"github.com/docker/distribution/manifest/schema2"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor"
|
"github.com/goharbor/harbor/src/api/artifact/processor"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/processor/blob"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
@ -35,9 +34,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
pc := &manifestV2Processor{
|
pc := &manifestV2Processor{}
|
||||||
blobFetcher: blob.Fcher,
|
|
||||||
}
|
|
||||||
pc.ManifestProcessor = base.NewManifestProcessor("created", "author", "architecture", "os")
|
pc.ManifestProcessor = base.NewManifestProcessor("created", "author", "architecture", "os")
|
||||||
mediaTypes := []string{
|
mediaTypes := []string{
|
||||||
v1.MediaTypeImageConfig,
|
v1.MediaTypeImageConfig,
|
||||||
@ -52,7 +49,6 @@ func init() {
|
|||||||
// manifestV2Processor processes image with OCI manifest and docker v2 manifest
|
// manifestV2Processor processes image with OCI manifest and docker v2 manifest
|
||||||
type manifestV2Processor struct {
|
type manifestV2Processor struct {
|
||||||
*base.ManifestProcessor
|
*base.ManifestProcessor
|
||||||
blobFetcher blob.Fetcher
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifestV2Processor) AbstractAddition(ctx context.Context, artifact *artifact.Artifact, addition string) (*processor.Addition, error) {
|
func (m *manifestV2Processor) AbstractAddition(ctx context.Context, artifact *artifact.Artifact, addition string) (*processor.Addition, error) {
|
||||||
@ -60,7 +56,11 @@ func (m *manifestV2Processor) AbstractAddition(ctx context.Context, artifact *ar
|
|||||||
return nil, ierror.New(nil).WithCode(ierror.BadRequestCode).
|
return nil, ierror.New(nil).WithCode(ierror.BadRequestCode).
|
||||||
WithMessage("addition %s isn't supported for %s(manifest version 2)", addition, ArtifactTypeImage)
|
WithMessage("addition %s isn't supported for %s(manifest version 2)", addition, ArtifactTypeImage)
|
||||||
}
|
}
|
||||||
_, content, err := m.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
|
mani, _, err := m.RegCli.PullManifest(artifact.RepositoryName, artifact.Digest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, content, err := mani.Payload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -68,12 +68,12 @@ func (m *manifestV2Processor) AbstractAddition(ctx context.Context, artifact *ar
|
|||||||
if err := json.Unmarshal(content, manifest); err != nil {
|
if err := json.Unmarshal(content, manifest); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
content, err = m.blobFetcher.FetchLayer(artifact.RepositoryName, manifest.Config.Digest.String())
|
_, blob, err := m.RegCli.PullBlob(artifact.RepositoryName, manifest.Config.Digest.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
image := &v1.Image{}
|
image := &v1.Image{}
|
||||||
if err := json.Unmarshal(content, image); err != nil {
|
if err := json.NewDecoder(blob).Decode(image); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
content, err = json.Marshal(image.History)
|
content, err = json.Marshal(image.History)
|
||||||
|
@ -15,10 +15,15 @@
|
|||||||
package image
|
package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/distribution"
|
||||||
|
"github.com/docker/distribution/manifest/schema2"
|
||||||
|
"github.com/goharbor/harbor/src/api/artifact/processor/base"
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/processor/blob"
|
"github.com/goharbor/harbor/src/testing/pkg/registry"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -120,15 +125,14 @@ var (
|
|||||||
|
|
||||||
type manifestV2ProcessorTestSuite struct {
|
type manifestV2ProcessorTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
processor *manifestV2Processor
|
processor *manifestV2Processor
|
||||||
blobFetcher *blob.FakeFetcher
|
regCli *registry.FakeClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifestV2ProcessorTestSuite) SetupTest() {
|
func (m *manifestV2ProcessorTestSuite) SetupTest() {
|
||||||
m.blobFetcher = &blob.FakeFetcher{}
|
m.regCli = ®istry.FakeClient{}
|
||||||
m.processor = &manifestV2Processor{
|
m.processor = &manifestV2Processor{}
|
||||||
blobFetcher: m.blobFetcher,
|
m.processor.ManifestProcessor = &base.ManifestProcessor{RegCli: m.regCli}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifestV2ProcessorTestSuite) TestAbstractAddition() {
|
func (m *manifestV2ProcessorTestSuite) TestAbstractAddition() {
|
||||||
@ -138,8 +142,10 @@ func (m *manifestV2ProcessorTestSuite) TestAbstractAddition() {
|
|||||||
|
|
||||||
// build history
|
// build history
|
||||||
artifact := &artifact.Artifact{}
|
artifact := &artifact.Artifact{}
|
||||||
m.blobFetcher.On("FetchManifest").Return("", []byte(manifest), nil)
|
manifest, _, err := distribution.UnmarshalManifest(schema2.MediaTypeManifest, []byte(manifest))
|
||||||
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
m.Require().Nil(err)
|
||||||
|
m.regCli.On("PullManifest").Return(manifest, "", nil)
|
||||||
|
m.regCli.On("PullBlob").Return(0, ioutil.NopCloser(strings.NewReader(config)), nil)
|
||||||
addition, err := m.processor.AbstractAddition(nil, artifact, AdditionTypeBuildHistory)
|
addition, err := m.processor.AbstractAddition(nil, artifact, AdditionTypeBuildHistory)
|
||||||
m.Require().Nil(err)
|
m.Require().Nil(err)
|
||||||
m.Equal("application/json; charset=utf-8", addition.ContentType)
|
m.Equal("application/json; charset=utf-8", addition.ContentType)
|
||||||
|
@ -135,8 +135,6 @@ func (c *controller) GetByName(ctx context.Context, name string) (*models.RepoRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) Delete(ctx context.Context, id int64) error {
|
func (c *controller) Delete(ctx context.Context, id int64) error {
|
||||||
// TODO how to make sure the logic included by middlewares(immutable, readonly, quota, etc)
|
|
||||||
// TODO is covered when deleting the artifacts of the repository
|
|
||||||
artifacts, err := c.artCtl.List(ctx, &q.Query{
|
artifacts, err := c.artCtl.List(ctx, &q.Query{
|
||||||
Keywords: map[string]interface{}{
|
Keywords: map[string]interface{}{
|
||||||
"RepositoryID": id,
|
"RepositoryID": id,
|
||||||
@ -151,8 +149,6 @@ func (c *controller) Delete(ctx context.Context, id int64) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c.repoMgr.Delete(ctx, id)
|
return c.repoMgr.Delete(ctx, id)
|
||||||
|
|
||||||
// TODO fire event
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) Update(ctx context.Context, repository *models.RepoRecord, properties ...string) error {
|
func (c *controller) Update(ctx context.Context, repository *models.RepoRecord, properties ...string) error {
|
||||||
|
@ -18,14 +18,15 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/docker/distribution"
|
|
||||||
"github.com/docker/distribution/manifest/manifestlist"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/distribution"
|
||||||
|
"github.com/docker/distribution/manifest/manifestlist"
|
||||||
// register oci manifest unmarshal function
|
// register oci manifest unmarshal function
|
||||||
_ "github.com/docker/distribution/manifest/ocischema"
|
_ "github.com/docker/distribution/manifest/ocischema"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
@ -87,7 +88,7 @@ type Client interface {
|
|||||||
Copy(srcRepository, srcReference, dstRepository, dstReference string, override bool) (err error)
|
Copy(srcRepository, srcReference, dstRepository, dstReference string, override bool) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO TODO support HTTPS
|
// TODO support HTTPS
|
||||||
|
|
||||||
// NewClient creates a registry client with the default authorizer which determines the auth scheme
|
// NewClient creates a registry client with the default authorizer which determines the auth scheme
|
||||||
// of the registry automatically and calls the corresponding underlying authorizers(basic/bearer) to
|
// of the registry automatically and calls the corresponding underlying authorizers(basic/bearer) to
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
// 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 blob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FakeFetcher is a fake blob fetcher that implement the src/api/artifact/abstractor/blob.Fetcher interface
|
|
||||||
type FakeFetcher struct {
|
|
||||||
mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchManifest ...
|
|
||||||
func (f *FakeFetcher) FetchManifest(repoFullName, digest string) (string, []byte, error) {
|
|
||||||
args := f.Called(mock.Anything)
|
|
||||||
return args.String(0), args.Get(1).([]byte), args.Error(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchLayer ...
|
|
||||||
func (f *FakeFetcher) FetchLayer(repoFullName, digest string) (content []byte, err error) {
|
|
||||||
args := f.Called(mock.Anything)
|
|
||||||
return args.Get(0).([]byte), args.Error(1)
|
|
||||||
}
|
|
@ -89,8 +89,8 @@ func (f *FakeClient) BlobExist(repository, digest string) (bool, error) {
|
|||||||
func (f *FakeClient) PullBlob(repository, digest string) (int64, io.ReadCloser, error) {
|
func (f *FakeClient) PullBlob(repository, digest string) (int64, io.ReadCloser, error) {
|
||||||
args := f.Called()
|
args := f.Called()
|
||||||
var blob io.ReadCloser
|
var blob io.ReadCloser
|
||||||
if args[0] != nil {
|
if args[1] != nil {
|
||||||
blob = args[0].(io.ReadCloser)
|
blob = args[1].(io.ReadCloser)
|
||||||
}
|
}
|
||||||
return int64(args.Int(0)), blob, args.Error(2)
|
return int64(args.Int(0)), blob, args.Error(2)
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,6 @@ Library Process
|
|||||||
Default Tags API
|
Default Tags API
|
||||||
|
|
||||||
*** Test Cases ***
|
*** Test Cases ***
|
||||||
|
|
||||||
# TODO the cases commented by "###" can be uncommented after implementing the repository python library based on new API
|
|
||||||
|
|
||||||
Test Case - LDAP Group Admin Role
|
Test Case - LDAP Group Admin Role
|
||||||
Harbor API Test ./tests/apitests/python/test_ldap_admin_role.py
|
Harbor API Test ./tests/apitests/python/test_ldap_admin_role.py
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user