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:
KubeSphere CI Bot
2025-03-19 11:03:58 +08:00
committed by GitHub
parent d412777b97
commit 1564abca4d
8 changed files with 539 additions and 8 deletions

View File

@@ -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
}

View File

@@ -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().