mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
Merge with origin master
This commit is contained in:
parent
ab6bb58c36
commit
dc96ded36a
@ -31,7 +31,6 @@ import (
|
||||
type ProjectAPI struct {
|
||||
BaseAPI
|
||||
userID int
|
||||
username string
|
||||
projectID int64
|
||||
}
|
||||
|
||||
@ -185,7 +184,6 @@ func (p *ProjectAPI) FilterAccessLog() {
|
||||
}
|
||||
p.Data["json"] = accessLogList
|
||||
|
||||
log.Errorf("--- accessLog first record: %v ---", accessLogList[0])
|
||||
p.ServeJSON()
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -26,6 +27,9 @@ import (
|
||||
"github.com/vmware/harbor/models"
|
||||
svc_utils "github.com/vmware/harbor/service/utils"
|
||||
"github.com/vmware/harbor/utils/log"
|
||||
"github.com/vmware/harbor/utils/registry"
|
||||
"github.com/vmware/harbor/utils/registry/auth"
|
||||
"github.com/vmware/harbor/utils/registry/errors"
|
||||
)
|
||||
|
||||
// RepositoryAPI handles request to /api/repositories /api/repositories/tags /api/repositories/manifests, the parm has to be put
|
||||
@ -36,6 +40,7 @@ type RepositoryAPI struct {
|
||||
BaseAPI
|
||||
userID int
|
||||
username string
|
||||
registry *registry.Registry
|
||||
}
|
||||
|
||||
// Prepare will set a non existent user ID in case the request tries to view repositories under a project he doesn't has permission.
|
||||
@ -53,6 +58,43 @@ func (ra *RepositoryAPI) Prepare() {
|
||||
} else {
|
||||
ra.username = username
|
||||
}
|
||||
|
||||
var client *http.Client
|
||||
|
||||
//no session, initialize a standard auth handler
|
||||
if ra.userID == dao.NonExistUserID && len(ra.username) == 0 {
|
||||
username, password, _ := ra.Ctx.Request.BasicAuth()
|
||||
|
||||
credential := auth.NewBasicAuthCredential(username, password)
|
||||
client = registry.NewClientStandardAuthHandlerEmbeded(credential)
|
||||
log.Debug("initializing standard auth handler")
|
||||
|
||||
} else {
|
||||
// session works, initialize a username auth handler
|
||||
username := ra.username
|
||||
if len(username) == 0 {
|
||||
user, err := dao.GetUser(models.User{
|
||||
UserID: ra.userID,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("error occurred whiling geting user for initializing a username auth handler: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
username = user.Username
|
||||
}
|
||||
|
||||
client = registry.NewClientUsernameAuthHandlerEmbeded(username)
|
||||
log.Debug("initializing username auth handler: %s", username)
|
||||
}
|
||||
|
||||
endpoint := os.Getenv("REGISTRY_URL")
|
||||
r, err := registry.New(endpoint, client)
|
||||
if err != nil {
|
||||
log.Fatalf("error occurred while initializing auth handler for repository API: %v", err)
|
||||
}
|
||||
|
||||
ra.registry = r
|
||||
}
|
||||
|
||||
// Get ...
|
||||
@ -77,11 +119,13 @@ func (ra *RepositoryAPI) Get() {
|
||||
ra.RenderError(http.StatusForbidden, "")
|
||||
return
|
||||
}
|
||||
|
||||
repoList, err := svc_utils.GetRepoFromCache()
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get repo from cache, error: %v", err)
|
||||
ra.RenderError(http.StatusInternalServerError, "internal sever error")
|
||||
}
|
||||
|
||||
projectName := p.Name
|
||||
q := ra.GetString("q")
|
||||
var resp []string
|
||||
@ -105,6 +149,56 @@ func (ra *RepositoryAPI) Get() {
|
||||
ra.ServeJSON()
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (ra *RepositoryAPI) Delete() {
|
||||
repoName := ra.GetString("repo_name")
|
||||
if len(repoName) == 0 {
|
||||
ra.CustomAbort(http.StatusBadRequest, "repo_name is nil")
|
||||
}
|
||||
|
||||
tags := []string{}
|
||||
tag := ra.GetString("tag")
|
||||
if len(tag) == 0 {
|
||||
tagList, err := ra.registry.ListTag(repoName)
|
||||
if err != nil {
|
||||
e, ok := errors.ParseError(err)
|
||||
if ok {
|
||||
log.Info(e)
|
||||
ra.CustomAbort(e.StatusCode, e.Message)
|
||||
} else {
|
||||
log.Error(err)
|
||||
ra.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||
}
|
||||
|
||||
}
|
||||
tags = append(tags, tagList...)
|
||||
|
||||
} else {
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
|
||||
for _, t := range tags {
|
||||
if err := ra.registry.DeleteTag(repoName, t); err != nil {
|
||||
e, ok := errors.ParseError(err)
|
||||
if ok {
|
||||
ra.CustomAbort(e.StatusCode, e.Message)
|
||||
} else {
|
||||
log.Error(err)
|
||||
ra.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||
}
|
||||
}
|
||||
log.Infof("delete tag: %s %s", repoName, t)
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Debug("refreshing catalog cache")
|
||||
if err := svc_utils.RefreshCatalogCache(); err != nil {
|
||||
log.Errorf("error occurred while refresh catalog cache: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
type tag struct {
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
@ -116,15 +210,18 @@ func (ra *RepositoryAPI) GetTags() {
|
||||
var tags []string
|
||||
|
||||
repoName := ra.GetString("repo_name")
|
||||
result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "tags", "list"), ra.username)
|
||||
tags, err := ra.registry.ListTag(repoName)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repoName, err)
|
||||
ra.RenderError(http.StatusInternalServerError, "Failed to get repo tags")
|
||||
} else {
|
||||
t := tag{}
|
||||
json.Unmarshal(result, &t)
|
||||
tags = t.Tags
|
||||
e, ok := errors.ParseError(err)
|
||||
if ok {
|
||||
log.Info(e)
|
||||
ra.CustomAbort(e.StatusCode, e.Message)
|
||||
} else {
|
||||
log.Error(err)
|
||||
ra.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||
}
|
||||
}
|
||||
|
||||
ra.Data["json"] = tags
|
||||
ra.ServeJSON()
|
||||
}
|
||||
@ -136,14 +233,19 @@ func (ra *RepositoryAPI) GetManifests() {
|
||||
|
||||
item := models.RepoItem{}
|
||||
|
||||
result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "manifests", tag), ra.username)
|
||||
_, _, payload, err := ra.registry.PullManifest(repoName, tag, registry.ManifestVersion1)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repoName, tag, err)
|
||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
e, ok := errors.ParseError(err)
|
||||
if ok {
|
||||
log.Info(e)
|
||||
ra.CustomAbort(e.StatusCode, e.Message)
|
||||
} else {
|
||||
log.Error(err)
|
||||
ra.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||
}
|
||||
}
|
||||
mani := models.Manifest{}
|
||||
err = json.Unmarshal(result, &mani)
|
||||
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")
|
||||
@ -157,7 +259,6 @@ func (ra *RepositoryAPI) GetManifests() {
|
||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
item.CreatedStr = item.Created.Format("2006-01-02 15:04:05")
|
||||
item.DurationDays = strconv.Itoa(int(time.Since(item.Created).Hours()/24)) + " days"
|
||||
|
||||
ra.Data["json"] = item
|
||||
|
@ -40,7 +40,6 @@ type Target struct {
|
||||
Digest string
|
||||
Repository string
|
||||
URL string `json:"Url"`
|
||||
Tag string
|
||||
}
|
||||
|
||||
// Actor holds information about actor.
|
||||
|
@ -29,7 +29,6 @@ type RepoItem struct {
|
||||
ID string `json:"Id"`
|
||||
Parent string `json:"Parent"`
|
||||
Created time.Time `json:"Created"`
|
||||
CreatedStr string `json:"CreatedStr"`
|
||||
DurationDays string `json:"Duration Days"`
|
||||
Author string `json:"Author"`
|
||||
Architecture string `json:"Architecture"`
|
||||
|
@ -17,6 +17,8 @@ package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -25,6 +27,8 @@ import (
|
||||
"github.com/vmware/harbor/models"
|
||||
svc_utils "github.com/vmware/harbor/service/utils"
|
||||
"github.com/vmware/harbor/utils/log"
|
||||
"github.com/vmware/harbor/utils/registry"
|
||||
"github.com/vmware/harbor/utils/registry/errors"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
@ -32,11 +36,7 @@ import (
|
||||
// NotificationHandler handles request on /service/notifications/, which listens to registry's events.
|
||||
type NotificationHandler struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
type taglist struct {
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
registry *registry.Registry
|
||||
}
|
||||
|
||||
const manifestPattern = `^application/vnd.docker.distribution.manifest.v\d\+json`
|
||||
@ -52,8 +52,9 @@ func (n *NotificationHandler) Post() {
|
||||
log.Errorf("error while decoding json: %v", err)
|
||||
return
|
||||
}
|
||||
var username, action, repo, project, repo_tag, tag_url string
|
||||
var username, action, repo, project, repo_tag, tag_url, digest string
|
||||
var matched bool
|
||||
var client *http.Client
|
||||
for _, e := range notification.Events {
|
||||
matched, err = regexp.MatchString(manifestPattern, e.Target.MediaType)
|
||||
if err != nil {
|
||||
@ -65,15 +66,27 @@ func (n *NotificationHandler) Post() {
|
||||
action = e.Action
|
||||
repo = e.Target.Repository
|
||||
tag_url = e.Target.URL
|
||||
result, err1 := svc_utils.RegistryAPIGet(tag_url, username)
|
||||
digest = e.Target.Digest
|
||||
|
||||
client = registry.NewClientUsernameAuthHandlerEmbeded(username)
|
||||
log.Debug("initializing username auth handler: %s", username)
|
||||
endpoint := os.Getenv("REGISTRY_URL")
|
||||
r, err1 := registry.New(endpoint, client)
|
||||
if err1 != nil {
|
||||
log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repo, tag_url, err1)
|
||||
log.Fatalf("error occurred while initializing auth handler for repository API: %v", err1)
|
||||
|
||||
}
|
||||
n.registry = r
|
||||
|
||||
_, _, payload, err2 := n.registry.PullManifest(repo, digest, registry.ManifestVersion1)
|
||||
|
||||
if err2 != nil {
|
||||
log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repo, tag_url, err2)
|
||||
return
|
||||
}
|
||||
|
||||
maniDig := models.ManifestDigest{}
|
||||
err = json.Unmarshal(result, &maniDig)
|
||||
err = json.Unmarshal(payload, &maniDig)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag_url, err)
|
||||
return
|
||||
@ -85,36 +98,48 @@ func (n *NotificationHandler) Post() {
|
||||
digestLayers = append(digestLayers, diglayer.Digest)
|
||||
}
|
||||
|
||||
result, err = svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repo, "tags", "list"), username)
|
||||
tags, err := n.registry.ListTag(repo)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repo, err)
|
||||
} else {
|
||||
t := taglist{}
|
||||
json.Unmarshal(result, &t)
|
||||
for _, tag := range t.Tags {
|
||||
result, err = svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repo, "manifests", tag), username)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repo, err)
|
||||
continue
|
||||
}
|
||||
taginfo := models.Manifest{}
|
||||
err = json.Unmarshal(result, &taginfo)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag, err)
|
||||
continue
|
||||
}
|
||||
for _, fslayer := range taginfo.FsLayers {
|
||||
tagLayers = append(tagLayers, fslayer.BlobSum)
|
||||
}
|
||||
|
||||
sort.Strings(digestLayers)
|
||||
sort.Strings(tagLayers)
|
||||
eq := compStringArray(digestLayers, tagLayers)
|
||||
if eq {
|
||||
repo_tag = tag
|
||||
break
|
||||
}
|
||||
e, ok := errors.ParseError(err)
|
||||
if ok {
|
||||
log.Info(e)
|
||||
} else {
|
||||
log.Error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("tags : %v ", tags)
|
||||
|
||||
for _, tag := range tags {
|
||||
_, _, payload, err := n.registry.PullManifest(repo, tag, registry.ManifestVersion1)
|
||||
if err != nil {
|
||||
e, ok := errors.ParseError(err)
|
||||
if ok {
|
||||
log.Info(e)
|
||||
} else {
|
||||
log.Error(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
taginfo := models.Manifest{}
|
||||
err = json.Unmarshal(payload, &taginfo)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag, err)
|
||||
continue
|
||||
}
|
||||
for _, fslayer := range taginfo.FsLayers {
|
||||
tagLayers = append(tagLayers, fslayer.BlobSum)
|
||||
}
|
||||
|
||||
sort.Strings(digestLayers)
|
||||
sort.Strings(tagLayers)
|
||||
eq := compStringArray(digestLayers, tagLayers)
|
||||
if eq {
|
||||
repo_tag = tag
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if strings.Contains(repo, "/") {
|
||||
|
Loading…
Reference in New Issue
Block a user