Merge pull request #622 from ywk253100/master_dev

return more information when calling get mannifest API
This commit is contained in:
Wenkai Yin 2016-08-02 11:21:00 +08:00 committed by GitHub
commit 35e14114a9
2 changed files with 47 additions and 81 deletions

View File

@ -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()
} }

View File

@ -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"`
}