harbor/src/pkg/reg/adapter/aliacr/openapi.go

307 lines
8.3 KiB
Go

// Copyright Project Harbor Authors
//
// 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 aliacr
import (
"encoding/json"
"fmt"
"strconv"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/cr"
"github.com/aliyun/alibaba-cloud-sdk-go/services/cr_ee"
)
type repository struct {
Name string
Namespace string
ID string
}
type authToken struct {
user string
password string
expiresAt time.Time
}
// openapi is an interface that defines methods for interacting with an open API.
type openapi interface {
// ListNamespace returns a list of all namespaces.
ListNamespace() ([]string, error)
// ListRepository returns a list of all repositories for a specified namespace.
ListRepository(namespaceName string) ([]*repository, error)
// ListRepoTag returns a list of all tags for a specified repository.
ListRepoTag(repo *repository) ([]string, error)
// GetAuthorizationToken returns the authorization token for repository.
GetAuthorizationToken() (*authToken, error)
}
type acrOpenapi struct {
client *cr.Client
domain string
}
var _ openapi = &acrOpenapi{}
// newAcrOpenapi creates a new acrOpenapi instance.
func newAcrOpenapi(accessKeyID string, accessKeySecret string, regionID string) (openapi, error) {
client, err := cr.NewClientWithAccessKey(regionID, accessKeyID, accessKeySecret)
if err != nil {
return nil, err
}
return &acrOpenapi{
client: client,
domain: fmt.Sprintf(endpointTpl, regionID),
}, nil
}
// ListNamespace returns a list of namespaces
func (acr *acrOpenapi) ListNamespace() ([]string, error) {
var namespaces []string
var nsReq = cr.CreateGetNamespaceListRequest()
var nsResp *cr.GetNamespaceListResponse
nsReq.SetDomain(acr.domain)
nsResp, err := acr.client.GetNamespaceList(nsReq)
if err != nil {
return nil, err
}
var resp = &aliACRNamespaceResp{}
err = json.Unmarshal(nsResp.GetHttpContentBytes(), resp)
if err != nil {
return nil, err
}
for _, ns := range resp.Data.Namespaces {
namespaces = append(namespaces, ns.Namespace)
}
return namespaces, nil
}
// ListRepository returns a list of repositories in the specified namespace
func (acr *acrOpenapi) ListRepository(namespaceName string) ([]*repository, error) {
var repos []*repository
var reposReq = cr.CreateGetRepoListByNamespaceRequest()
reposReq.SetDomain(acr.domain)
reposReq.RepoNamespace = namespaceName
var page = 1
for {
reposReq.Page = requests.NewInteger(page)
reposResp, err := acr.client.GetRepoListByNamespace(reposReq)
if err != nil {
return nil, err
}
var resp = &aliReposResp{}
err = json.Unmarshal(reposResp.GetHttpContentBytes(), resp)
if err != nil {
return nil, err
}
for _, repo := range resp.Data.Repos {
repos = append(repos, &repository{
Name: repo.RepoName,
Namespace: repo.RepoNamespace,
})
}
if resp.Data.Total-(resp.Data.Page*resp.Data.PageSize) <= 0 {
break
}
page++
}
return repos, nil
}
// ListRepoTag returns a list of tags in the specified repository
func (acr *acrOpenapi) ListRepoTag(repo *repository) ([]string, error) {
var tags []string
var tagsReq = cr.CreateGetRepoTagsRequest()
tagsReq.SetDomain(acr.domain)
tagsReq.RepoNamespace = repo.Namespace
tagsReq.RepoName = repo.Name
var page = 1
for {
tagsReq.Page = requests.NewInteger(page)
tagsResp, err := acr.client.GetRepoTags(tagsReq)
if err != nil {
return nil, err
}
var resp = &aliTagResp{}
err = json.Unmarshal(tagsResp.GetHttpContentBytes(), resp)
if err != nil {
return nil, err
}
for _, tag := range resp.Data.Tags {
tags = append(tags, tag.Tag)
}
if resp.Data.Total-(resp.Data.Page*resp.Data.PageSize) <= 0 {
break
}
page++
}
return tags, nil
}
// GetAuthorizationToken returns the authorization token for repository.
func (acr *acrOpenapi) GetAuthorizationToken() (*authToken, error) {
var tokenRequest = cr.CreateGetAuthorizationTokenRequest()
var tokenResponse *cr.GetAuthorizationTokenResponse
tokenRequest.SetDomain(acr.domain)
tokenResponse, err := acr.client.GetAuthorizationToken(tokenRequest)
if err != nil {
return nil, err
}
var v authorizationToken
err = json.Unmarshal(tokenResponse.GetHttpContentBytes(), &v)
if err != nil {
return nil, err
}
return &authToken{
user: v.Data.TempUserName,
password: v.Data.AuthorizationToken,
expiresAt: v.Data.ExpireDate.ToTime(),
}, nil
}
type acreeOpenapi struct {
client *cr_ee.Client
domain string
instanceID string
}
var _ openapi = &acreeOpenapi{}
// newAcreeOpenapi creates a new acreeOpenapi instance.
func newAcreeOpenapi(accessKeyID string, accessKeySecret string, regionID string, instanceID string) (openapi, error) {
client, err := cr_ee.NewClientWithAccessKey(regionID, accessKeyID, accessKeySecret)
if err != nil {
return nil, err
}
return &acreeOpenapi{
client: client,
domain: fmt.Sprintf(endpointTpl, regionID),
instanceID: instanceID,
}, nil
}
// ListNamespace returns a list of namespaces
func (acree *acreeOpenapi) ListNamespace() ([]string, error) {
var namespaces []string
var nsReq = cr_ee.CreateListNamespaceRequest()
nsReq.SetDomain(acree.domain)
nsReq.InstanceId = acree.instanceID
var page = 1
for {
nsReq.PageNo = requests.NewInteger(page)
nsResp, err := acree.client.ListNamespace(nsReq)
if err != nil {
return nil, err
}
for _, ns := range nsResp.Namespaces {
namespaces = append(namespaces, ns.NamespaceName)
}
total, err := strconv.Atoi(nsResp.TotalCount)
if err != nil {
return nil, err
}
if total-(nsResp.PageNo*nsResp.PageSize) <= 0 {
break
}
page++
}
return namespaces, nil
}
// ListRepository returns a list of repositories in the specified namespace
func (acree *acreeOpenapi) ListRepository(namespaceName string) ([]*repository, error) {
var repos []*repository
var reposReq = cr_ee.CreateListRepositoryRequest()
reposReq.SetDomain(acree.domain)
reposReq.InstanceId = acree.instanceID
reposReq.RepoNamespaceName = namespaceName
reposReq.RepoStatus = "NORMAL"
var page = 1
for {
reposReq.PageNo = requests.NewInteger(page)
reposResp, err := acree.client.ListRepository(reposReq)
if err != nil {
return nil, err
}
for _, repo := range reposResp.Repositories {
repos = append(repos, &repository{
Name: repo.RepoName,
Namespace: repo.RepoNamespaceName,
ID: repo.RepoId,
})
}
total, err := strconv.Atoi(reposResp.TotalCount)
if err != nil {
return nil, err
}
if total-(reposResp.PageNo*reposResp.PageSize) <= 0 {
break
}
page++
}
return repos, nil
}
// ListRepoTag returns a list of tags in the specified repository
func (acree *acreeOpenapi) ListRepoTag(repo *repository) ([]string, error) {
var tags []string
var tagsReq = cr_ee.CreateListRepoTagRequest()
tagsReq.SetDomain(acree.domain)
tagsReq.InstanceId = acree.instanceID
tagsReq.RepoId = repo.ID
var page = 1
for {
tagsReq.PageNo = requests.NewInteger(page)
tagsResp, err := acree.client.ListRepoTag(tagsReq)
if err != nil {
return nil, err
}
for _, image := range tagsResp.Images {
tags = append(tags, image.Tag)
}
total, err := strconv.Atoi(tagsResp.TotalCount)
if err != nil {
return nil, err
}
if total-(tagsResp.PageNo*tagsResp.PageSize) <= 0 {
break
}
page++
}
return tags, nil
}
// GetAuthorizationToken returns the authorization token for repository.
func (acree *acreeOpenapi) GetAuthorizationToken() (*authToken, error) {
var tokenRequest = cr_ee.CreateGetAuthorizationTokenRequest()
// FIXME: use vpc endpoint if vpc is enabled
tokenRequest.SetDomain(acree.domain)
tokenRequest.InstanceId = acree.instanceID
tokenResponse, err := acree.client.GetAuthorizationToken(tokenRequest)
if err != nil {
return nil, err
}
return &authToken{
user: tokenResponse.TempUsername,
password: tokenResponse.AuthorizationToken,
expiresAt: time.Unix(tokenResponse.ExpireTime/1000, 0),
}, nil
}