feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -25,7 +25,7 @@ import (
"sync"
"time"
openapi_v2 "github.com/google/gnostic/openapiv2"
openapi_v2 "github.com/google/gnostic-models/openapiv2"
"k8s.io/klog/v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

View File

@@ -22,7 +22,7 @@ import (
"sync"
"syscall"
openapi_v2 "github.com/google/gnostic/openapiv2"
openapi_v2 "github.com/google/gnostic-models/openapiv2"
errorsutil "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -33,6 +33,7 @@ import (
"k8s.io/client-go/openapi"
cachedopenapi "k8s.io/client-go/openapi/cached"
restclient "k8s.io/client-go/rest"
"k8s.io/klog/v2"
)
type cacheEntry struct {
@@ -61,6 +62,15 @@ var (
ErrCacheNotFound = errors.New("not found")
)
// Server returning empty ResourceList for Group/Version.
type emptyResponseError struct {
gv string
}
func (e *emptyResponseError) Error() string {
return fmt.Sprintf("received empty response for: %s", e.gv)
}
var _ discovery.CachedDiscoveryInterface = &memCacheClient{}
// isTransientConnectionError checks whether given error is "Connection refused" or
@@ -103,7 +113,13 @@ func (d *memCacheClient) ServerResourcesForGroupVersion(groupVersion string) (*m
if cachedVal.err != nil && isTransientError(cachedVal.err) {
r, err := d.serverResourcesForGroupVersion(groupVersion)
if err != nil {
utilruntime.HandleError(fmt.Errorf("couldn't get resource list for %v: %v", groupVersion, err))
// Don't log "empty response" as an error; it is a common response for metrics.
if _, emptyErr := err.(*emptyResponseError); emptyErr {
// Log at same verbosity as disk cache.
klog.V(3).Infof("%v", err)
} else {
utilruntime.HandleError(fmt.Errorf("couldn't get resource list for %v: %v", groupVersion, err))
}
}
cachedVal = &cacheEntry{r, err}
d.groupToServerResources[groupVersion] = cachedVal
@@ -120,32 +136,38 @@ func (d *memCacheClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*meta
// GroupsAndMaybeResources returns the list of APIGroups, and possibly the map of group/version
// to resources. The returned groups will never be nil, but the resources map can be nil
// if there are no cached resources.
func (d *memCacheClient) GroupsAndMaybeResources() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) {
func (d *memCacheClient) GroupsAndMaybeResources() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, map[schema.GroupVersion]error, error) {
d.lock.Lock()
defer d.lock.Unlock()
if !d.cacheValid {
if err := d.refreshLocked(); err != nil {
return nil, nil, err
return nil, nil, nil, err
}
}
// Build the resourceList from the cache?
var resourcesMap map[schema.GroupVersion]*metav1.APIResourceList
var failedGVs map[schema.GroupVersion]error
if d.receivedAggregatedDiscovery && len(d.groupToServerResources) > 0 {
resourcesMap = map[schema.GroupVersion]*metav1.APIResourceList{}
failedGVs = map[schema.GroupVersion]error{}
for gv, cacheEntry := range d.groupToServerResources {
groupVersion, err := schema.ParseGroupVersion(gv)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse group version (%v): %v", gv, err)
return nil, nil, nil, fmt.Errorf("failed to parse group version (%v): %v", gv, err)
}
if cacheEntry.err != nil {
failedGVs[groupVersion] = cacheEntry.err
} else {
resourcesMap[groupVersion] = cacheEntry.resourceList
}
resourcesMap[groupVersion] = cacheEntry.resourceList
}
}
return d.groupList, resourcesMap, nil
return d.groupList, resourcesMap, failedGVs, nil
}
func (d *memCacheClient) ServerGroups() (*metav1.APIGroupList, error) {
groups, _, err := d.GroupsAndMaybeResources()
groups, _, _, err := d.GroupsAndMaybeResources()
if err != nil {
return nil, err
}
@@ -219,7 +241,8 @@ func (d *memCacheClient) refreshLocked() error {
if ad, ok := d.delegate.(discovery.AggregatedDiscoveryInterface); ok {
var resources map[schema.GroupVersion]*metav1.APIResourceList
gl, resources, err = ad.GroupsAndMaybeResources()
var failedGVs map[schema.GroupVersion]error
gl, resources, failedGVs, err = ad.GroupsAndMaybeResources()
if resources != nil && err == nil {
// Cache the resources.
d.groupToServerResources = map[string]*cacheEntry{}
@@ -227,6 +250,10 @@ func (d *memCacheClient) refreshLocked() error {
for gv, resources := range resources {
d.groupToServerResources[gv.String()] = &cacheEntry{resources, nil}
}
// Cache GroupVersion discovery errors
for gv, err := range failedGVs {
d.groupToServerResources[gv.String()] = &cacheEntry{nil, err}
}
d.receivedAggregatedDiscovery = true
d.cacheValid = true
return nil
@@ -252,7 +279,13 @@ func (d *memCacheClient) refreshLocked() error {
r, err := d.serverResourcesForGroupVersion(gv)
if err != nil {
utilruntime.HandleError(fmt.Errorf("couldn't get resource list for %v: %v", gv, err))
// Don't log "empty response" as an error; it is a common response for metrics.
if _, emptyErr := err.(*emptyResponseError); emptyErr {
// Log at same verbosity as disk cache.
klog.V(3).Infof("%v", err)
} else {
utilruntime.HandleError(fmt.Errorf("couldn't get resource list for %v: %v", gv, err))
}
}
resultLock.Lock()
@@ -274,7 +307,7 @@ func (d *memCacheClient) serverResourcesForGroupVersion(groupVersion string) (*m
return r, err
}
if len(r.APIResources) == 0 {
return r, fmt.Errorf("Got empty response for: %v", groupVersion)
return r, &emptyResponseError{gv: groupVersion}
}
return r, nil
}