mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-19 07:07:42 +01:00
Merge pull request #622 from ywk253100/master_dev
return more information when calling get mannifest API
This commit is contained in:
commit
35e14114a9
@ -16,16 +16,16 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
|
"github.com/docker/distribution/manifest/schema2"
|
||||||
"github.com/vmware/harbor/dao"
|
"github.com/vmware/harbor/dao"
|
||||||
"github.com/vmware/harbor/models"
|
"github.com/vmware/harbor/models"
|
||||||
"github.com/vmware/harbor/service/cache"
|
"github.com/vmware/harbor/service/cache"
|
||||||
@ -270,6 +270,15 @@ func (ra *RepositoryAPI) GetManifests() {
|
|||||||
ra.CustomAbort(http.StatusBadRequest, "repo_name or tag is nil")
|
ra.CustomAbort(http.StatusBadRequest, "repo_name or tag is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version := ra.GetString("version")
|
||||||
|
if len(version) == 0 {
|
||||||
|
version = "v2"
|
||||||
|
}
|
||||||
|
|
||||||
|
if version != "v1" && version != "v2" {
|
||||||
|
ra.CustomAbort(http.StatusBadRequest, "version should be v1 or v2")
|
||||||
|
}
|
||||||
|
|
||||||
projectName := getProjectName(repoName)
|
projectName := getProjectName(repoName)
|
||||||
project, err := dao.GetProjectByName(projectName)
|
project, err := dao.GetProjectByName(projectName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -290,10 +299,20 @@ func (ra *RepositoryAPI) GetManifests() {
|
|||||||
ra.CustomAbort(http.StatusInternalServerError, "internal error")
|
ra.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
item := models.RepoItem{}
|
result := struct {
|
||||||
|
Manifest interface{} `json:"manifest"`
|
||||||
|
Config interface{} `json:"config,omitempty" `
|
||||||
|
}{}
|
||||||
|
|
||||||
mediaTypes := []string{schema1.MediaTypeManifest}
|
mediaTypes := []string{}
|
||||||
_, _, payload, err := rc.PullManifest(tag, mediaTypes)
|
switch version {
|
||||||
|
case "v1":
|
||||||
|
mediaTypes = append(mediaTypes, schema1.MediaTypeManifest)
|
||||||
|
case "v2":
|
||||||
|
mediaTypes = append(mediaTypes, schema2.MediaTypeManifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, mediaType, payload, err := rc.PullManifest(tag, mediaTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if regErr, ok := err.(*registry_error.Error); ok {
|
if regErr, ok := err.(*registry_error.Error); ok {
|
||||||
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
|
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
|
||||||
@ -302,24 +321,33 @@ func (ra *RepositoryAPI) GetManifests() {
|
|||||||
log.Errorf("error occurred while getting manifest of %s:%s: %v", repoName, tag, err)
|
log.Errorf("error occurred while getting manifest of %s:%s: %v", repoName, tag, err)
|
||||||
ra.CustomAbort(http.StatusInternalServerError, "internal error")
|
ra.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||||
}
|
}
|
||||||
mani := models.Manifest{}
|
|
||||||
err = json.Unmarshal(payload, &mani)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repoName, tag, err)
|
|
||||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v1Compatibility := mani.History[0].V1Compatibility
|
|
||||||
|
|
||||||
err = json.Unmarshal([]byte(v1Compatibility), &item)
|
manifest, _, err := registry.UnMarshal(mediaType, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to decode V1 field for repo, repo name: %s, tag: %s, error: %v", repoName, tag, err)
|
log.Errorf("an error occurred while parsing manifest of %s:%s: %v", repoName, tag, err)
|
||||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
item.DurationDays = strconv.Itoa(int(time.Since(item.Created).Hours()/24)) + " days"
|
|
||||||
|
|
||||||
ra.Data["json"] = item
|
result.Manifest = manifest
|
||||||
|
|
||||||
|
deserializedmanifest, ok := manifest.(*schema2.DeserializedManifest)
|
||||||
|
if ok {
|
||||||
|
_, data, err := rc.PullBlob(deserializedmanifest.Target().Digest.String())
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get config of manifest %s:%s: %v", repoName, tag, err)
|
||||||
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadAll(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to read config of manifest %s:%s: %v", repoName, tag, err)
|
||||||
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Config = string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
ra.Data["json"] = result
|
||||||
ra.ServeJSON()
|
ra.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
|
||||||
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 models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Repo holds information about repositories.
|
|
||||||
type Repo struct {
|
|
||||||
Repositories []string `json:"repositories"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RepoItem holds manifest of an image.
|
|
||||||
type RepoItem struct {
|
|
||||||
ID string `json:"Id"`
|
|
||||||
Parent string `json:"Parent"`
|
|
||||||
Created time.Time `json:"Created"`
|
|
||||||
DurationDays string `json:"Duration Days"`
|
|
||||||
Author string `json:"Author"`
|
|
||||||
Architecture string `json:"Architecture"`
|
|
||||||
DockerVersion string `json:"Docker Version"`
|
|
||||||
Os string `json:"OS"`
|
|
||||||
//Size int `json:"Size"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag holds information about a tag.
|
|
||||||
type Tag struct {
|
|
||||||
Version string `json:"version"`
|
|
||||||
ImageID string `json:"image_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Manifest ...
|
|
||||||
type Manifest struct {
|
|
||||||
SchemaVersion int `json:"schemaVersion"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Tag string `json:"tag"`
|
|
||||||
Architecture string `json:"architecture"`
|
|
||||||
FsLayers []blobSumItem `json:"fsLayers"`
|
|
||||||
History []histroyItem `json:"history"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type histroyItem struct {
|
|
||||||
V1Compatibility string `json:"v1Compatibility"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type blobSumItem struct {
|
|
||||||
BlobSum string `json:"blobSum"`
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user