Files
KubePi/pkg/util/imagerepo/repos/harbor.go

280 lines
6.4 KiB
Go

package repos
import (
"encoding/json"
"fmt"
"strconv"
"strings"
)
const (
v2Url = "api/v2.0"
v1Url = "api"
projectUrl = "/projects"
repositoryUrl = "repositories"
artifactUrl = "/artifacts"
tagUrl = "tags"
)
func NewHarborClient(endpoint, username, password, version string) *harborClient {
return &harborClient{
EndPoint: endpoint,
HttpClient: &HttpClient{
Username: username,
Password: password,
Host: endpoint,
},
Version: version,
}
}
type harborClient struct {
EndPoint string
HttpClient *HttpClient
Version string
}
type artifacts struct {
Type string
Tags []NameResult
}
type harborBody struct {
Name string
Version string
Format string
ProjectID int `json:"project_id"`
ArtifactCount int `json:"artifact_count"`
TagsCount int `json:"tags_count"`
}
func (c *harborClient) ListRepos(request ProjectRequest) (names []string, err error) {
projectUrl := fmt.Sprintf("%s?page=%d&page_size=%d", getProjectUrl(c.Version), request.Page, request.Limit)
if request.Name != "" {
if c.Version == "v2" {
projectUrl = projectUrl + "&q=name=~" + request.Name
} else {
projectUrl = projectUrl + "&name=" + request.Name
}
}
body, _, err := c.HttpClient.Get(projectUrl)
if err != nil {
return
}
var projects []harborBody
if err = json.Unmarshal(body, &projects); err != nil {
return
}
for _, r := range projects {
names = append(names, r.Name)
}
return
}
const LIMIT = 100
func (c *harborClient) ListImages(request RepoRequest) (response RepoResponse, err error) {
project := request.Repo
startCount := (request.Page - 1) * request.Limit
start := true
p := 1
artifactCount := 0
repoArCount := 0
artifactStart := 0
var repos []harborBody
for start {
var repoUrl string
if c.Version == "v2" {
repoUrl = fmt.Sprintf("%s/%s/%s?page=%d&&page_size=%d", getProjectUrl(c.Version), project, repositoryUrl, p, LIMIT)
} else {
result, err1 := c.HttpClient.GetNameResult(getProjectUrl(c.Version))
if err1 != nil {
err = err1
return
}
for _, value := range result {
if value.Name == project {
repoUrl = fmt.Sprintf("%s/%s%s", v1Url, repositoryUrl, "?project_id="+strconv.Itoa(value.ProjectID))
break
}
}
}
body, _, err1 := c.HttpClient.Get(repoUrl)
if err1 != nil {
err = err1
return
}
var items []harborBody
if err1 = json.Unmarshal(body, &items); err1 != nil {
err = err1
return
}
if len(items) < LIMIT {
start = false
}
for _, v := range items {
count := v.ArtifactCount
if c.Version == "v1" {
count = v.TagsCount
}
if count == 0 {
continue
}
artifactCount = artifactCount + count
if artifactCount > startCount {
repos = append(repos, v)
repoArCount = repoArCount + count
if repoArCount >= request.Limit {
start = false
break
}
continue
}
if artifactCount >= startCount {
artifactStart = artifactCount - startCount
}
}
p++
}
var repoUrl string
if c.Version == "v2" {
repoUrl = fmt.Sprintf("%s/%s/%s", getProjectUrl(c.Version), project, repositoryUrl)
}
var items []string
for _, r := range repos {
var tagsUrl string
if c.Version == "v2" {
repoName := strings.Replace(r.Name, project+"/", "", -1)
tagsUrl = fmt.Sprintf("%s/%s/%s?page=%d&&page_size=%d", repoUrl, repoName, artifactUrl, 1, r.ArtifactCount)
} else {
tagsUrl = fmt.Sprintf("%s/%s/%s/%s", v1Url, repositoryUrl, r.Name, tagUrl)
}
body, res, err2 := c.HttpClient.Get(tagsUrl)
if res != nil && res.StatusCode == 404 {
continue
}
if err2 != nil {
if strings.Contains(err2.Error(), "404") {
continue
}
err = err2
return
}
if c.Version == "v2" {
var artifacts []artifacts
if err = json.Unmarshal(body, &artifacts); err != nil {
return
}
for _, art := range artifacts {
for _, tag := range art.Tags {
items = append(items, r.Name+":"+tag.Name)
}
}
} else {
var tags []NameResult
if err = json.Unmarshal(body, &tags); err != nil {
return
}
for _, tag := range tags {
items = append(items, r.Name+":"+tag.Name)
}
}
}
artifactEnd := artifactStart + request.Limit
if artifactStart+request.Limit > len(items) {
artifactEnd = len(items)
}
if artifactStart > artifactEnd {
response.Items = []string{}
return
}
response.Items = items[artifactStart:artifactEnd]
if len(response.Items) == request.Limit {
response.ContinueToken = "continue"
}
return
}
func (c *harborClient) ListImagesWithoutPage(project string) (images []string, err error) {
if c.Version == "v2" {
repoUrl := fmt.Sprintf("%s/%s/%s?page=1&&page_size=100", getProjectUrl(c.Version), project, repositoryUrl)
result, _, err1 := c.HttpClient.Get(repoUrl)
if err1 != nil {
err = err1
return
}
var items []harborBody
if err1 = json.Unmarshal(result, &items); err1 != nil {
err = err1
return
}
repoUrl = fmt.Sprintf("%s/%s/%s", getProjectUrl(c.Version), project, repositoryUrl)
for _, r := range items {
repoName := strings.Replace(r.Name, project+"/", "", -1)
body, _, err2 := c.HttpClient.Get(fmt.Sprintf("%s/%s/%s?page=1&&page_size=%d", repoUrl, repoName, artifactUrl, r.TagsCount))
if err2 != nil {
if strings.Contains(err2.Error(), "404") {
continue
}
err = err2
return
}
var artifacts []artifacts
if err = json.Unmarshal(body, &artifacts); err != nil {
return
}
for _, art := range artifacts {
for _, tag := range art.Tags {
images = append(images, r.Name+":"+tag.Name)
}
}
}
} else {
result, err1 := c.HttpClient.GetNameResult(getProjectUrl(c.Version))
if err1 != nil {
err = err1
return
}
var repoUrl string
for _, value := range result {
if value.Name == project {
repoUrl = fmt.Sprintf("%s/%s%s", v1Url, repositoryUrl, "?project_id="+strconv.Itoa(value.ProjectID))
break
}
}
repos, err1 := c.HttpClient.GetNameResult(repoUrl)
if err1 != nil {
err = err1
return
}
for _, repo := range repos {
tagUrl := fmt.Sprintf("%s/%s/%s/%s", v1Url, repositoryUrl, repo.Name, tagUrl)
tags, err1 := c.HttpClient.GetNameResult(tagUrl)
if err1 != nil {
err = err1
return
}
for _, tag := range tags {
images = append(images, repo.Name+":"+tag.Name)
}
}
}
return
}
func getProjectUrl(version string) string {
if version == "v1" {
return v1Url + projectUrl
} else {
return v2Url + projectUrl
}
}