4a425b1b创建于 2024年1月25日历史提交
package controller

import (
	"context"
	"github.com/google/go-containerregistry/pkg/authn"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"github.com/google/go-containerregistry/pkg/v1/remote/transport"
	"strings"
	"time"

	"crypto/tls"
	apimodel "github.com/goodrain/rainbond/api/model"
	"github.com/goodrain/rainbond/api/util/bcode"
	"github.com/goodrain/rainbond/builder/sources/registry"
	httputil "github.com/goodrain/rainbond/util/http"
	"github.com/sirupsen/logrus"
	"net/http"
	"net/url"
)

// Registry -
type Registry struct {
}

// RepositoryTags -
type RepositoryTags struct {
	Registry   string   `json:"registry"`
	Repository string   `json:"repository"`
	Tags       []string `json:"tags"`
	Total      int      `json:"total"`
}

// CheckRegistry 根据镜像仓库账号密码 检查镜像仓库是否可用
func (r2 *Registry) CheckRegistry(w http.ResponseWriter, r *http.Request) {
	var req apimodel.SearchByDomainRequest
	ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &req, nil)
	if !ok {
		return
	}

	if !strings.Contains(req.Domain, "://") {
		req.Domain = "//" + req.Domain
	}

	parse, err := url.Parse(req.Domain)
	if err != nil {
		logrus.Errorf("parse url error %s", err.Error())
		httputil.ReturnBcodeError(r, w, bcode.NewBadRequest(err.Error()))
		return
	}

	options := make([]name.Option, 0)
	if parse.Scheme == "http" {
		options = append(options, name.Insecure)
	}
	tr := http.DefaultTransport.(*http.Transport).Clone()
	tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}

	registryCfg, err := name.NewRegistry(parse.Host, options...)
	if err != nil {
		logrus.Errorf("parse registry error %s", err.Error())
		httputil.ReturnBcodeError(r, w, bcode.NewBadRequest(err.Error()))
		return
	}
	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
	defer cancel()
	_, err = transport.NewWithContext(ctx, registryCfg, &authn.Basic{
		Username: req.UserName,
		Password: req.Password,
	}, tr, []string{})
	if err != nil {
		logrus.Errorf("check registry error %s", err.Error())
		httputil.ReturnBcodeError(r, w, bcode.NewBadRequest(err.Error()))
		return
	}

	httputil.ReturnSuccess(r, w, true)
}

// GetAllRepo 根据镜像仓库账号密码 获取所有的镜像仓库
func (r2 *Registry) GetAllRepo(w http.ResponseWriter, r *http.Request) {
	var req apimodel.SearchByDomainRequest
	ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &req, nil)
	if !ok {
		return
	}
	c, err := registry.NewInsecure(req.Domain, req.UserName, req.Password)
	if err != nil {
		httputil.ReturnBcodeError(r, w, bcode.NewBadRequest(err.Error()))
		logrus.Errorf("get repositories error %s", err.Error())
		return
	}
	repositories, err := c.Repositories()
	if err != nil {
		httputil.ReturnBcodeError(r, w, bcode.NewBadRequest(err.Error()))
		logrus.Errorf("get repositories error %s", err.Error())
		return
	}
	httputil.ReturnSuccess(r, w, repositories)
}

// GetTagsByRepoName 根据镜像仓库账号密码 获取镜像tags
func (r2 *Registry) GetTagsByRepoName(w http.ResponseWriter, r *http.Request) {
	var req apimodel.SearchByDomainRequest
	ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &req, nil)
	if !ok {
		return
	}
	var regURL string
	if strings.HasSuffix(req.Domain, "/") {
		regURL = req.Domain + r.URL.Query().Get("repo")
	} else {
		regURL = req.Domain + "/" + r.URL.Query().Get("repo")
	}
	repo, err := name.NewRepository(regURL)
	if err != nil {
		logrus.Errorf("parse registry error %s", err.Error())
		httputil.ReturnBcodeError(r, w, bcode.NewBadRequest(err.Error()))
		return
	}

	authenticator := authn.FromConfig(authn.AuthConfig{
		Username: req.UserName,
		Password: req.Password,
	})

	tags, err := remote.List(repo, remote.WithAuth(authenticator))
	if err != nil {
		logrus.Errorf("get tags error %s", err.Error())
		httputil.ReturnBcodeError(r, w, bcode.NewBadRequest(err.Error()))
		return
	}
	httputil.ReturnSuccess(r, w, &RepositoryTags{
		Registry:   repo.RegistryStr(),
		Repository: repo.RepositoryStr(),
		Tags:       tags,
		Total:      len(tags),
	})
}