mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-02 21:11:37 +01:00
Request repository and tag list in parallel
When using S3 or others as the registry storage, the request for repository and tag list may be very slow. This commit fixes this by parallel requesting the resources.
This commit is contained in:
parent
b537ea96f3
commit
6243fed8f5
@ -154,12 +154,27 @@ func getRepositories(query *models.RepositoryQuery) ([]*repoResp, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return assembleRepos(repositories)
|
return assembleReposInParallel(repositories), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func assembleRepos(repositories []*models.RepoRecord) ([]*repoResp, error) {
|
func assembleReposInParallel(repositories []*models.RepoRecord) []*repoResp {
|
||||||
result := []*repoResp{}
|
c := make(chan *repoResp)
|
||||||
for _, repository := range repositories {
|
for _, repository := range repositories {
|
||||||
|
go assembleRepo(c, repository)
|
||||||
|
}
|
||||||
|
result := []*repoResp{}
|
||||||
|
var item *repoResp
|
||||||
|
for i := 0; i < len(repositories); i++ {
|
||||||
|
item = <-c
|
||||||
|
if item == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func assembleRepo(c chan *repoResp, repository *models.RepoRecord) {
|
||||||
repo := &repoResp{
|
repo := &repoResp{
|
||||||
ID: repository.RepositoryID,
|
ID: repository.RepositoryID,
|
||||||
Name: repository.Name,
|
Name: repository.Name,
|
||||||
@ -173,9 +188,10 @@ func assembleRepos(repositories []*models.RepoRecord) ([]*repoResp, error) {
|
|||||||
|
|
||||||
tags, err := getTags(repository.Name)
|
tags, err := getTags(repository.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.Errorf("failed to list tags of %s: %v", repository.Name, err)
|
||||||
}
|
} else {
|
||||||
repo.TagsCount = int64(len(tags))
|
repo.TagsCount = int64(len(tags))
|
||||||
|
}
|
||||||
|
|
||||||
labels, err := dao.GetLabelsOfResource(common.ResourceTypeRepository, repository.RepositoryID)
|
labels, err := dao.GetLabelsOfResource(common.ResourceTypeRepository, repository.RepositoryID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -184,9 +200,7 @@ func assembleRepos(repositories []*models.RepoRecord) ([]*repoResp, error) {
|
|||||||
repo.Labels = labels
|
repo.Labels = labels
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, repo)
|
c <- repo
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete ...
|
// Delete ...
|
||||||
@ -381,7 +395,7 @@ func (ra *RepositoryAPI) GetTag() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := assembleTags(client, repository, []string{tag},
|
result := assembleTagsInParallel(client, repository, []string{tag},
|
||||||
ra.SecurityCtx.GetUsername())
|
ra.SecurityCtx.GetUsername())
|
||||||
ra.Data["json"] = result[0]
|
ra.Data["json"] = result[0]
|
||||||
ra.ServeJSON()
|
ra.ServeJSON()
|
||||||
@ -453,16 +467,15 @@ func (ra *RepositoryAPI) GetTags() {
|
|||||||
tags = ts
|
tags = ts
|
||||||
}
|
}
|
||||||
|
|
||||||
ra.Data["json"] = assembleTags(client, repoName, tags,
|
ra.Data["json"] = assembleTagsInParallel(client, repoName, tags,
|
||||||
ra.SecurityCtx.GetUsername())
|
ra.SecurityCtx.GetUsername())
|
||||||
ra.ServeJSON()
|
ra.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
// get config, signature and scan overview and assemble them into one
|
// get config, signature and scan overview and assemble them into one
|
||||||
// struct for each tag in tags
|
// struct for each tag in tags
|
||||||
func assembleTags(client *registry.Repository, repository string,
|
func assembleTagsInParallel(client *registry.Repository, repository string,
|
||||||
tags []string, username string) []*tagResp {
|
tags []string, username string) []*tagResp {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
signatures := map[string][]notary.Target{}
|
signatures := map[string][]notary.Target{}
|
||||||
if config.WithNotary() {
|
if config.WithNotary() {
|
||||||
@ -473,12 +486,29 @@ func assembleTags(client *registry.Repository, repository string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c := make(chan *tagResp)
|
||||||
|
for _, tag := range tags {
|
||||||
|
go assembleTag(c, client, repository, tag, config.WithClair(),
|
||||||
|
config.WithNotary(), signatures)
|
||||||
|
}
|
||||||
result := []*tagResp{}
|
result := []*tagResp{}
|
||||||
for _, t := range tags {
|
var item *tagResp
|
||||||
item := &tagResp{}
|
for i := 0; i < len(tags); i++ {
|
||||||
|
item = <-c
|
||||||
|
if item == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func assembleTag(c chan *tagResp, client *registry.Repository,
|
||||||
|
repository, tag string, clairEnabled, notaryEnabled bool,
|
||||||
|
signatures map[string][]notary.Target) {
|
||||||
|
item := &tagResp{}
|
||||||
// labels
|
// labels
|
||||||
image := fmt.Sprintf("%s:%s", repository, t)
|
image := fmt.Sprintf("%s:%s", repository, tag)
|
||||||
labels, err := dao.GetLabelsOfResource(common.ResourceTypeImage, image)
|
labels, err := dao.GetLabelsOfResource(common.ResourceTypeImage, image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get labels of image %s: %v", image, err)
|
log.Errorf("failed to get labels of image %s: %v", image, err)
|
||||||
@ -487,21 +517,21 @@ func assembleTags(client *registry.Repository, repository string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the detail information of tag
|
// the detail information of tag
|
||||||
tagDetail, err := getTagDetail(client, t)
|
tagDetail, err := getTagDetail(client, tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get v2 manifest of %s:%s: %v", repository, t, err)
|
log.Errorf("failed to get v2 manifest of %s:%s: %v", repository, tag, err)
|
||||||
}
|
}
|
||||||
if tagDetail != nil {
|
if tagDetail != nil {
|
||||||
item.tagDetail = *tagDetail
|
item.tagDetail = *tagDetail
|
||||||
}
|
}
|
||||||
|
|
||||||
// scan overview
|
// scan overview
|
||||||
if config.WithClair() {
|
if clairEnabled {
|
||||||
item.ScanOverview = getScanOverview(item.Digest, item.Name)
|
item.ScanOverview = getScanOverview(item.Digest, item.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// signature, compare both digest and tag
|
// signature, compare both digest and tag
|
||||||
if config.WithNotary() {
|
if notaryEnabled && signatures != nil {
|
||||||
if sigs, ok := signatures[item.Digest]; ok {
|
if sigs, ok := signatures[item.Digest]; ok {
|
||||||
for _, sig := range sigs {
|
for _, sig := range sigs {
|
||||||
if item.Name == sig.Tag {
|
if item.Name == sig.Tag {
|
||||||
@ -510,11 +540,7 @@ func assembleTags(client *registry.Repository, repository string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
c <- item
|
||||||
result = append(result, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTagDetail returns the detail information for v2 manifest image
|
// getTagDetail returns the detail information for v2 manifest image
|
||||||
@ -709,13 +735,7 @@ func (ra *RepositoryAPI) GetTopRepos() {
|
|||||||
ra.CustomAbort(http.StatusInternalServerError, "internal server error")
|
ra.CustomAbort(http.StatusInternalServerError, "internal server error")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := assembleRepos(repos)
|
ra.Data["json"] = assembleReposInParallel(repos)
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to popultate tags count to repositories: %v", err)
|
|
||||||
ra.CustomAbort(http.StatusInternalServerError, "internal server error")
|
|
||||||
}
|
|
||||||
|
|
||||||
ra.Data["json"] = result
|
|
||||||
ra.ServeJSON()
|
ra.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user