mirror of
https://github.com/Quiq/docker-registry-ui
synced 2025-10-07 07:30:53 +08:00
Amend tag info page, change logging.
* Amend representation of the tag info page * Change logging library, add "-log-level" argument and put most of the logging into DEBUG mode
This commit is contained in:
79
main.go
79
main.go
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/quiq/docker-registry-ui/events"
|
||||
"github.com/quiq/docker-registry-ui/registry"
|
||||
"github.com/robfig/cron"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/tidwall/gjson"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
@@ -53,16 +54,23 @@ type apiClient struct {
|
||||
|
||||
func main() {
|
||||
var (
|
||||
a apiClient
|
||||
configFile string
|
||||
purgeTags bool
|
||||
purgeDryRun bool
|
||||
a apiClient
|
||||
|
||||
configFile, loggingLevel string
|
||||
purgeTags, purgeDryRun bool
|
||||
)
|
||||
flag.StringVar(&configFile, "config-file", "config.yml", "path to the config file")
|
||||
flag.StringVar(&loggingLevel, "log-level", "info", "logging level")
|
||||
flag.BoolVar(&purgeTags, "purge-tags", false, "purge old tags instead of running a web server")
|
||||
flag.BoolVar(&purgeDryRun, "dry-run", false, "dry-run for purging task, does not delete anything")
|
||||
flag.Parse()
|
||||
|
||||
if loggingLevel != "info" {
|
||||
if level, err := logrus.ParseLevel(loggingLevel); err == nil {
|
||||
logrus.SetLevel(level)
|
||||
}
|
||||
}
|
||||
|
||||
// Read config file.
|
||||
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
||||
panic(err)
|
||||
@@ -209,17 +217,35 @@ func (a *apiClient) viewTagInfo(c echo.Context) error {
|
||||
repoPath = fmt.Sprintf("%s/%s", namespace, repo)
|
||||
}
|
||||
|
||||
// Retrieve full image info from various versions of manifests
|
||||
sha256, infoV1, infoV2 := a.client.TagInfo(repoPath, tag, false)
|
||||
manifests := a.client.Manifests(repoPath, tag)
|
||||
sha256list, manifests := a.client.ManifestList(repoPath, tag)
|
||||
if (infoV1 == "" || infoV2 == "") && len(manifests) == 0 {
|
||||
return c.Redirect(http.StatusSeeOther, fmt.Sprintf("%s/%s/%s", a.config.BasePath, namespace, repo))
|
||||
}
|
||||
isListOnly := (infoV1 == "" && infoV2 == "")
|
||||
newRepoPath := gjson.Get(infoV1, "name").String()
|
||||
if newRepoPath != "" {
|
||||
repoPath = newRepoPath
|
||||
|
||||
created := gjson.Get(gjson.Get(infoV1, "history.0.v1Compatibility").String(), "created").String()
|
||||
isDigest := strings.HasPrefix(tag, "sha256:")
|
||||
if len(manifests) > 0 {
|
||||
sha256 = sha256list
|
||||
}
|
||||
|
||||
// Gather layers v2
|
||||
var layersV2 []map[string]gjson.Result
|
||||
for _, s := range gjson.Get(infoV2, "layers").Array() {
|
||||
layersV2 = append(layersV2, s.Map())
|
||||
}
|
||||
|
||||
// Gather layers v1
|
||||
var layersV1 []map[string]interface{}
|
||||
for _, s := range gjson.Get(infoV1, "history.#.v1Compatibility").Array() {
|
||||
m, _ := gjson.Parse(s.String()).Value().(map[string]interface{})
|
||||
// Sort key in the map to show the ordered on UI.
|
||||
m["ordered_keys"] = registry.SortedMapKeys(m)
|
||||
layersV1 = append(layersV1, m)
|
||||
}
|
||||
|
||||
// Count image size
|
||||
var imageSize int64
|
||||
if gjson.Get(infoV2, "layers").Exists() {
|
||||
for _, s := range gjson.Get(infoV2, "layers.#.size").Array() {
|
||||
@@ -231,56 +257,45 @@ func (a *apiClient) viewTagInfo(c echo.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
var layersV2 []map[string]gjson.Result
|
||||
for _, s := range gjson.Get(infoV2, "layers").Array() {
|
||||
layersV2 = append(layersV2, s.Map())
|
||||
}
|
||||
|
||||
var layersV1 []map[string]interface{}
|
||||
for _, s := range gjson.Get(infoV1, "history.#.v1Compatibility").Array() {
|
||||
m, _ := gjson.Parse(s.String()).Value().(map[string]interface{})
|
||||
// Sort key in the map to show the ordered on UI.
|
||||
m["ordered_keys"] = registry.SortedMapKeys(m)
|
||||
layersV1 = append(layersV1, m)
|
||||
}
|
||||
|
||||
// Count layers
|
||||
layersCount := len(layersV2)
|
||||
if layersCount == 0 {
|
||||
layersCount = len(gjson.Get(infoV1, "fsLayers").Array())
|
||||
}
|
||||
|
||||
isDigest := strings.HasPrefix(tag, "sha256:")
|
||||
var digests []map[string]interface{}
|
||||
// Gather sub-image info of multi-arch image
|
||||
var digestList []map[string]interface{}
|
||||
for _, s := range manifests {
|
||||
r, _ := gjson.Parse(s.String()).Value().(map[string]interface{})
|
||||
if s.Get("mediaType").String() == "application/vnd.docker.distribution.manifest.v2+json" {
|
||||
_, _, dInfo := a.client.TagInfo(repoPath, s.Get("digest").String(), false)
|
||||
_, dInfoV1, _ := a.client.TagInfo(repoPath, s.Get("digest").String(), true)
|
||||
var dSize int64
|
||||
for _, d := range gjson.Get(dInfo, "layers.#.size").Array() {
|
||||
for _, d := range gjson.Get(dInfoV1, "layers.#.size").Array() {
|
||||
dSize = dSize + d.Int()
|
||||
}
|
||||
r["size"] = dSize
|
||||
} else {
|
||||
r["size"] = s.Get("size").Int()
|
||||
}
|
||||
delete(r, "mediaType")
|
||||
r["ordered_keys"] = registry.SortedMapKeys(r)
|
||||
digests = append(digests, r)
|
||||
digestList = append(digestList, r)
|
||||
}
|
||||
|
||||
// Populate template vars
|
||||
data := jet.VarMap{}
|
||||
data.Set("namespace", namespace)
|
||||
data.Set("repo", repo)
|
||||
data.Set("sha256", sha256)
|
||||
data.Set("imageSize", imageSize)
|
||||
data.Set("tag", tag)
|
||||
data.Set("repoPath", repoPath)
|
||||
data.Set("created", gjson.Get(gjson.Get(infoV1, "history.0.v1Compatibility").String(), "created").String())
|
||||
data.Set("sha256", sha256)
|
||||
data.Set("imageSize", imageSize)
|
||||
data.Set("created", created)
|
||||
data.Set("layersCount", layersCount)
|
||||
data.Set("layersV2", layersV2)
|
||||
data.Set("layersV1", layersV1)
|
||||
data.Set("isDigest", isDigest)
|
||||
data.Set("isListOnly", isListOnly)
|
||||
data.Set("digests", digests)
|
||||
data.Set("digestList", digestList)
|
||||
|
||||
return c.Render(http.StatusOK, "tag_info.html", data)
|
||||
}
|
||||
|
Reference in New Issue
Block a user