feat: add imagesearch provider (#6449)
* feat: add imagesearch provider * update * update * update * update url and queries * add func getProviderTypeByHost --------- Signed-off-by: wenhaozhou <wenhaozhou@yunify.com> Signed-off-by: hongming <coder.scala@gmail.com> Co-authored-by: wenhaozhou <wenhaozhou@yunify.com>
This commit is contained in:
committed by
GitHub
parent
d412777b97
commit
1564abca4d
@@ -14,11 +14,15 @@ import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
"kubesphere.io/kubesphere/pkg/models/components"
|
||||
"kubesphere.io/kubesphere/pkg/models/registries/imagesearch"
|
||||
"kubesphere.io/kubesphere/pkg/models/registries/imagesearch/dockerhub"
|
||||
"kubesphere.io/kubesphere/pkg/models/registries/imagesearch/harbor"
|
||||
v2 "kubesphere.io/kubesphere/pkg/models/registries/v2"
|
||||
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/overview"
|
||||
@@ -41,10 +45,12 @@ var (
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
resourceGetterV1alpha3 *resourcev1alpha3.Getter
|
||||
componentsGetter components.Getter
|
||||
registryHelper v2.RegistryHelper
|
||||
counter overview.Counter
|
||||
resourceGetterV1alpha3 *resourcev1alpha3.Getter
|
||||
componentsGetter components.Getter
|
||||
registryHelper v2.RegistryHelper
|
||||
counter overview.Counter
|
||||
imageSearchController *imagesearch.Controller
|
||||
imageSearchSecretGetter imagesearch.SecretGetter
|
||||
}
|
||||
|
||||
func (h *handler) GetResources(request *restful.Request, response *restful.Response) {
|
||||
@@ -221,6 +227,49 @@ func (h *handler) GetNamespaceOverview(request *restful.Request, response *restf
|
||||
_ = response.WriteEntity(metrics)
|
||||
}
|
||||
|
||||
func (h *handler) SearchImages(request *restful.Request, response *restful.Response) {
|
||||
imageName := request.QueryParameter("q")
|
||||
namespace := request.PathParameter("namespace")
|
||||
searchSecret := request.QueryParameter("secret")
|
||||
|
||||
var (
|
||||
config = &imagesearch.SearchConfig{}
|
||||
err error
|
||||
provider imagesearch.SearchProvider
|
||||
)
|
||||
if searchSecret != "" {
|
||||
config, err = h.imageSearchSecretGetter.GetSecretConfig(request.Request.Context(), searchSecret, namespace)
|
||||
if err != nil {
|
||||
api.HandleError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
if config.ProviderType == "" {
|
||||
config.ProviderType = getProviderTypeByHost(config.Host)
|
||||
}
|
||||
|
||||
var exist bool
|
||||
provider, exist = h.imageSearchController.GetProvider(config.ProviderType)
|
||||
if !exist {
|
||||
api.HandleNotFound(response, request, errors.NewNotFound(schema.GroupResource{
|
||||
Resource: "imageSearchProvider",
|
||||
}, config.ProviderType))
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
provider = h.imageSearchController.GetDefaultProvider()
|
||||
}
|
||||
|
||||
results, err := provider.Search(imageName, *config)
|
||||
if err != nil {
|
||||
api.HandleError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
_ = response.WriteEntity(results)
|
||||
}
|
||||
|
||||
func canonicalizeRegistryError(request *restful.Request, response *restful.Response, err error) {
|
||||
if strings.Contains(err.Error(), "Unauthorized") {
|
||||
api.HandleUnauthorized(response, request, err)
|
||||
@@ -230,3 +279,10 @@ func canonicalizeRegistryError(request *restful.Request, response *restful.Respo
|
||||
api.HandleBadRequest(response, request, err)
|
||||
}
|
||||
}
|
||||
|
||||
func getProviderTypeByHost(host string) string {
|
||||
if host == imagesearch.HostDockerIo {
|
||||
return dockerhub.DockerHubRegisterProvider
|
||||
}
|
||||
return harbor.HarborRegisterProvider
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import (
|
||||
v2 "kubesphere.io/kubesphere/pkg/models/registries/v2"
|
||||
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/overview"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/registries/imagesearch"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -39,10 +41,12 @@ func Resource(resource string) schema.GroupResource {
|
||||
|
||||
func NewHandler(cacheReader runtimeclient.Reader, counter overview.Counter, k8sVersion *semver.Version) rest.Handler {
|
||||
return &handler{
|
||||
resourceGetterV1alpha3: resourcev1alpha3.NewResourceGetter(cacheReader, k8sVersion),
|
||||
componentsGetter: components.NewComponentsGetter(cacheReader),
|
||||
registryHelper: v2.NewRegistryHelper(),
|
||||
counter: counter,
|
||||
resourceGetterV1alpha3: resourcev1alpha3.NewResourceGetter(cacheReader, k8sVersion),
|
||||
componentsGetter: components.NewComponentsGetter(cacheReader),
|
||||
registryHelper: v2.NewRegistryHelper(),
|
||||
imageSearchController: imagesearch.SharedImageSearchProviderController,
|
||||
counter: counter,
|
||||
imageSearchSecretGetter: imagesearch.NewSecretGetter(cacheReader),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +141,15 @@ func (h *handler) AddToContainer(c *restful.Container) error {
|
||||
Reads(v1.Secret{}).
|
||||
Returns(http.StatusOK, api.StatusOK, v1.Secret{}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/images").
|
||||
To(h.SearchImages).
|
||||
Doc("Search image from a registry").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{api.TagNamespacedResources}).
|
||||
Param(ws.PathParameter("namespace", "The specified namespace.")).
|
||||
Param(ws.QueryParameter("secret", "Secret name of the image repository credential, left empty means anonymous fetch.").Required(false)).
|
||||
Param(ws.QueryParameter("q", "Search parameter for project and repository name.")).
|
||||
Returns(http.StatusOK, api.StatusOK, imagesearch.Results{}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/imageconfig").
|
||||
To(h.GetImageConfig).
|
||||
Deprecate().
|
||||
|
||||
36
pkg/models/registries/imagesearch/configuration.go
Normal file
36
pkg/models/registries/imagesearch/configuration.go
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Please refer to the LICENSE file in the root directory of the project.
|
||||
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package imagesearch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
SecretDataKey = "configuration.yaml"
|
||||
)
|
||||
|
||||
type Configuration struct {
|
||||
// The provider name.
|
||||
Name string `json:"name" yaml:"name"`
|
||||
|
||||
// The type of image search provider
|
||||
Type string `json:"type" yaml:"type"`
|
||||
|
||||
// The options of image search provider
|
||||
ProviderOptions map[string]interface{} `json:"provider" yaml:"provider"`
|
||||
}
|
||||
|
||||
func UnmarshalFrom(secret *v1.Secret) (*Configuration, error) {
|
||||
config := &Configuration{}
|
||||
if err := yaml.Unmarshal(secret.Data[SecretDataKey], config); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal secret data: %s", err)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
132
pkg/models/registries/imagesearch/controller.go
Normal file
132
pkg/models/registries/imagesearch/controller.go
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Please refer to the LICENSE file in the root directory of the project.
|
||||
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package imagesearch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
toolscache "k8s.io/client-go/tools/cache"
|
||||
"k8s.io/klog/v2"
|
||||
runtimecache "sigs.k8s.io/controller-runtime/pkg/cache"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
)
|
||||
|
||||
var SharedImageSearchProviderController = NewController()
|
||||
|
||||
const (
|
||||
dockerHubRegisterProvider = "DockerHubRegistryProvider"
|
||||
harborRegisterProvider = "HarborRegistryProvider"
|
||||
|
||||
SecretTypeImageSearchProvider = "config.kubesphere.io/imagesearchprovider"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
imageSearchProviders *sync.Map
|
||||
imageSearchProviderConfig *sync.Map
|
||||
}
|
||||
|
||||
func NewController() *Controller {
|
||||
return &Controller{
|
||||
imageSearchProviders: &sync.Map{},
|
||||
imageSearchProviderConfig: &sync.Map{}}
|
||||
}
|
||||
|
||||
func (c *Controller) WatchConfigurationChanges(ctx context.Context, cache runtimecache.Cache) error {
|
||||
informer, err := cache.GetInformer(ctx, &v1.Secret{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("get informer failed: %w", err)
|
||||
}
|
||||
|
||||
c.initGenericProvider()
|
||||
|
||||
_, err = informer.AddEventHandler(toolscache.FilteringResourceEventHandler{
|
||||
FilterFunc: func(obj interface{}) bool {
|
||||
return IsImageSearchProviderConfiguration(obj.(*v1.Secret))
|
||||
},
|
||||
Handler: &toolscache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
c.OnConfigurationChange(obj.(*v1.Secret))
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
c.OnConfigurationChange(new.(*v1.Secret))
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
c.OnConfigurationDelete(obj.(*v1.Secret))
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("add event handler failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) GetDefaultProvider() SearchProvider {
|
||||
provider, _ := c.imageSearchProviders.Load(dockerHubRegisterProvider)
|
||||
return provider.(SearchProvider)
|
||||
}
|
||||
|
||||
func (c *Controller) initGenericProvider() {
|
||||
dockerHubProvider, _ := searchProviderFactories[dockerHubRegisterProvider].Create(nil)
|
||||
c.imageSearchProviders.Store(dockerHubRegisterProvider, dockerHubProvider)
|
||||
|
||||
harborProvider, _ := searchProviderFactories[harborRegisterProvider].Create(nil)
|
||||
c.imageSearchProviders.Store(harborRegisterProvider, harborProvider)
|
||||
}
|
||||
|
||||
func IsImageSearchProviderConfiguration(secret *v1.Secret) bool {
|
||||
if secret.Namespace != constants.KubeSphereNamespace {
|
||||
return false
|
||||
}
|
||||
return secret.Type == SecretTypeImageSearchProvider
|
||||
}
|
||||
|
||||
func (c *Controller) OnConfigurationDelete(secret *v1.Secret) {
|
||||
configuration, err := UnmarshalFrom(secret)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to unmarshal secret data: %s", err)
|
||||
return
|
||||
}
|
||||
c.imageSearchProviders.Delete(configuration.Name)
|
||||
c.imageSearchProviderConfig.Delete(configuration.Name)
|
||||
}
|
||||
|
||||
func (c *Controller) OnConfigurationChange(secret *v1.Secret) {
|
||||
configuration, err := UnmarshalFrom(secret)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to unmarshal secret data: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if factory, ok := searchProviderFactories[configuration.Type]; ok {
|
||||
if provider, err := factory.Create(configuration.ProviderOptions); err != nil {
|
||||
klog.Error(fmt.Sprintf("failed to create image search provider %s: %s", configuration.Name, err))
|
||||
} else {
|
||||
c.imageSearchProviders.Store(configuration.Name, provider)
|
||||
c.imageSearchProviderConfig.Store(configuration.Name, configuration)
|
||||
klog.V(4).Infof("create image search provider %s successfully", configuration.Name)
|
||||
}
|
||||
} else {
|
||||
klog.Errorf("image search provider %s with type %s is not supported", configuration.Name, configuration.Type)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c *Controller) GetProvider(providerName string) (SearchProvider, bool) {
|
||||
if obj, ok := c.imageSearchProviders.Load(providerName); ok {
|
||||
if provider, ok := obj.(SearchProvider); ok {
|
||||
return provider, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
99
pkg/models/registries/imagesearch/dockerhub/provider.go
Normal file
99
pkg/models/registries/imagesearch/dockerhub/provider.go
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Please refer to the LICENSE file in the root directory of the project.
|
||||
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package dockerhub
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/registries/imagesearch"
|
||||
)
|
||||
|
||||
const (
|
||||
DockerHubRegisterProvider = "DockerHubRegistryProvider"
|
||||
dockerHubSearchUrl = "v2/search/repositories?query=%s"
|
||||
dockerHubHost = "https://hub.docker.com"
|
||||
)
|
||||
|
||||
func init() {
|
||||
imagesearch.RegistrySearchProvider(&dockerHubSearchProviderFactory{})
|
||||
}
|
||||
|
||||
var _ imagesearch.SearchProvider = &dockerHubSearchProvider{}
|
||||
|
||||
type dockerHubSearchProvider struct {
|
||||
HttpClient *http.Client `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
type searchResponse struct {
|
||||
Results []result `json:"results"`
|
||||
}
|
||||
|
||||
type result struct {
|
||||
RepoName string `json:"repo_name"`
|
||||
}
|
||||
|
||||
func (d dockerHubSearchProvider) Search(imageName string, config imagesearch.SearchConfig) (*imagesearch.Results, error) {
|
||||
url := fmt.Sprintf("%s/%s", dockerHubHost, fmt.Sprintf(dockerHubSearchUrl, imageName))
|
||||
request, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.Username != "" {
|
||||
authCode := fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", config.Username, config.Password))))
|
||||
request.Header.Set("Authorization", authCode)
|
||||
}
|
||||
|
||||
resp, err := d.HttpClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
klog.Errorf("search images failed with status code: %d, %s", resp.StatusCode, string(bytes))
|
||||
return nil, fmt.Errorf("search images failed with status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
searchResp := &searchResponse{}
|
||||
err = json.Unmarshal(bytes, searchResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imageResult := &imagesearch.Results{
|
||||
Entries: make([]string, 0),
|
||||
}
|
||||
for _, v := range searchResp.Results {
|
||||
imageResult.Entries = append(imageResult.Entries, v.RepoName)
|
||||
}
|
||||
|
||||
imageResult.Total = int64(len(imageResult.Entries))
|
||||
|
||||
return imageResult, nil
|
||||
}
|
||||
|
||||
var _ imagesearch.SearchProviderFactory = &dockerHubSearchProviderFactory{}
|
||||
|
||||
type dockerHubSearchProviderFactory struct{}
|
||||
|
||||
func (d dockerHubSearchProviderFactory) Type() string {
|
||||
return DockerHubRegisterProvider
|
||||
}
|
||||
|
||||
func (d dockerHubSearchProviderFactory) Create(_ map[string]interface{}) (imagesearch.SearchProvider, error) {
|
||||
var provider dockerHubSearchProvider
|
||||
provider.HttpClient = http.DefaultClient
|
||||
return provider, nil
|
||||
}
|
||||
106
pkg/models/registries/imagesearch/harbor/provider.go
Normal file
106
pkg/models/registries/imagesearch/harbor/provider.go
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Please refer to the LICENSE file in the root directory of the project.
|
||||
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package harbor
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/registries/imagesearch"
|
||||
)
|
||||
|
||||
const (
|
||||
HarborRegisterProvider = "HarborRegistryProvider"
|
||||
harborSearchUrl = "api/v2.0/search?q=%s"
|
||||
)
|
||||
|
||||
func init() {
|
||||
imagesearch.RegistrySearchProvider(&harborRegistrySearchProviderFactory{})
|
||||
}
|
||||
|
||||
var _ imagesearch.SearchProvider = &harborRegistrySearchProvider{}
|
||||
|
||||
type harborRegistrySearchProvider struct {
|
||||
HttpClient *http.Client `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
type searchResponse struct {
|
||||
Repository []repository `json:"repository"`
|
||||
}
|
||||
|
||||
type repository struct {
|
||||
RepositoryName string `json:"repository_name"`
|
||||
}
|
||||
|
||||
func (d harborRegistrySearchProvider) Search(imageName string, config imagesearch.SearchConfig) (*imagesearch.Results, error) {
|
||||
|
||||
url := fmt.Sprintf("%s/%s", config.Host, fmt.Sprintf(harborSearchUrl, imageName))
|
||||
|
||||
request, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.Username != "" {
|
||||
authCode := fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", config.Username, config.Password))))
|
||||
request.Header.Set("Authorization", authCode)
|
||||
}
|
||||
resp, err := d.HttpClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
klog.Errorf("search images failed with status code: %d, %s", resp.StatusCode, string(bytes))
|
||||
return nil, fmt.Errorf("search images failed with status code: %d, message: %s", resp.StatusCode, bytes)
|
||||
}
|
||||
|
||||
searchResp := &searchResponse{}
|
||||
err = json.Unmarshal(bytes, searchResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imageResult := &imagesearch.Results{
|
||||
Entries: make([]string, 0),
|
||||
}
|
||||
for _, v := range searchResp.Repository {
|
||||
imageResult.Entries = append(imageResult.Entries, v.RepositoryName)
|
||||
}
|
||||
|
||||
imageResult.Total = int64(len(imageResult.Entries))
|
||||
|
||||
return imageResult, nil
|
||||
}
|
||||
|
||||
var _ imagesearch.SearchProviderFactory = &harborRegistrySearchProviderFactory{}
|
||||
|
||||
type harborRegistrySearchProviderFactory struct{}
|
||||
|
||||
func (d harborRegistrySearchProviderFactory) Type() string {
|
||||
return HarborRegisterProvider
|
||||
}
|
||||
|
||||
func (d harborRegistrySearchProviderFactory) Create(_ map[string]interface{}) (imagesearch.SearchProvider, error) {
|
||||
var provider harborRegistrySearchProvider
|
||||
provider.HttpClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
return provider, nil
|
||||
}
|
||||
84
pkg/models/registries/imagesearch/registry_provider.go
Normal file
84
pkg/models/registries/imagesearch/registry_provider.go
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Please refer to the LICENSE file in the root directory of the project.
|
||||
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package imagesearch
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
const (
|
||||
HostDockerIo = "https://docker.io"
|
||||
)
|
||||
|
||||
var (
|
||||
searchProviderFactories = make(map[string]SearchProviderFactory)
|
||||
)
|
||||
|
||||
type SearchProvider interface {
|
||||
Search(imageName string, config SearchConfig) (*Results, error)
|
||||
}
|
||||
|
||||
type Results struct {
|
||||
Total int64 `json:"total"`
|
||||
Entries []string `json:"entries"`
|
||||
}
|
||||
|
||||
type SearchConfig struct {
|
||||
Host string
|
||||
ProviderType string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
type SearchProviderFactory interface {
|
||||
Type() string
|
||||
Create(options map[string]interface{}) (SearchProvider, error)
|
||||
}
|
||||
|
||||
func RegistrySearchProvider(factory SearchProviderFactory) {
|
||||
searchProviderFactories[factory.Type()] = factory
|
||||
}
|
||||
|
||||
type SecretGetter interface {
|
||||
GetSecretConfig(ctx context.Context, name, namespace string) (*SearchConfig, error)
|
||||
}
|
||||
|
||||
func NewSecretGetter(reader client.Reader) SecretGetter {
|
||||
return &secretGetter{reader}
|
||||
}
|
||||
|
||||
type secretGetter struct {
|
||||
client.Reader
|
||||
}
|
||||
|
||||
// {"auths":{"https://harbor.172.31.19.17.nip.io":{"username":"admin","password":"Harbor12345","email":"","auth":"YWRtaW46SGFyYm9yMTIzNDU="}}}
|
||||
|
||||
func (s *secretGetter) GetSecretConfig(ctx context.Context, name, namespace string) (*SearchConfig, error) {
|
||||
secret := &corev1.Secret{}
|
||||
err := s.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
provider := secret.Annotations[SecretTypeImageSearchProvider]
|
||||
|
||||
data := secret.Data[".dockerconfigjson"]
|
||||
auths := jsoniter.Get(data, "auths")
|
||||
|
||||
host := auths.Keys()[0]
|
||||
username := auths.Get(host, "username").ToString()
|
||||
password := auths.Get(host, "password").ToString()
|
||||
return &SearchConfig{
|
||||
Host: host,
|
||||
ProviderType: provider,
|
||||
Username: username,
|
||||
Password: password,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user