mirror of
				https://github.com/kubernetes/client-go.git
				synced 2025-11-04 07:50:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			197 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2017 The Kubernetes 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 scale
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
 | 
						|
	"k8s.io/apimachinery/pkg/api/meta"
 | 
						|
	"k8s.io/apimachinery/pkg/runtime"
 | 
						|
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						|
	serializer "k8s.io/apimachinery/pkg/runtime/serializer"
 | 
						|
	"k8s.io/client-go/discovery"
 | 
						|
	scalescheme "k8s.io/client-go/scale/scheme"
 | 
						|
	scaleappsint "k8s.io/client-go/scale/scheme/appsint"
 | 
						|
	scaleappsv1beta1 "k8s.io/client-go/scale/scheme/appsv1beta1"
 | 
						|
	scaleappsv1beta2 "k8s.io/client-go/scale/scheme/appsv1beta2"
 | 
						|
	scaleautoscaling "k8s.io/client-go/scale/scheme/autoscalingv1"
 | 
						|
	scaleextint "k8s.io/client-go/scale/scheme/extensionsint"
 | 
						|
	scaleext "k8s.io/client-go/scale/scheme/extensionsv1beta1"
 | 
						|
)
 | 
						|
 | 
						|
// PreferredResourceMapper determines the preferred version of a resource to scale
 | 
						|
type PreferredResourceMapper interface {
 | 
						|
	// ResourceFor takes a partial resource and returns the preferred resource.
 | 
						|
	ResourceFor(resource schema.GroupVersionResource) (preferredResource schema.GroupVersionResource, err error)
 | 
						|
}
 | 
						|
 | 
						|
// Ensure a RESTMapper satisfies the PreferredResourceMapper interface
 | 
						|
var _ PreferredResourceMapper = meta.RESTMapper(nil)
 | 
						|
 | 
						|
// ScaleKindResolver knows about the relationship between
 | 
						|
// resources and the GroupVersionKind of their scale subresources.
 | 
						|
type ScaleKindResolver interface {
 | 
						|
	// ScaleForResource returns the GroupVersionKind of the
 | 
						|
	// scale subresource for the given GroupVersionResource.
 | 
						|
	ScaleForResource(resource schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error)
 | 
						|
}
 | 
						|
 | 
						|
// discoveryScaleResolver is a ScaleKindResolver that uses
 | 
						|
// a DiscoveryInterface to associate resources with their
 | 
						|
// scale-kinds
 | 
						|
type discoveryScaleResolver struct {
 | 
						|
	discoveryClient discovery.ServerResourcesInterface
 | 
						|
}
 | 
						|
 | 
						|
func (r *discoveryScaleResolver) ScaleForResource(inputRes schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error) {
 | 
						|
	groupVerResources, err := r.discoveryClient.ServerResourcesForGroupVersion(inputRes.GroupVersion().String())
 | 
						|
	if err != nil {
 | 
						|
		return schema.GroupVersionKind{}, fmt.Errorf("unable to fetch discovery information for %s: %v", inputRes.String(), err)
 | 
						|
	}
 | 
						|
 | 
						|
	for _, resource := range groupVerResources.APIResources {
 | 
						|
		resourceParts := strings.SplitN(resource.Name, "/", 2)
 | 
						|
		if len(resourceParts) != 2 || resourceParts[0] != inputRes.Resource || resourceParts[1] != "scale" {
 | 
						|
			// skip non-scale resources, or scales for resources that we're not looking for
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		scaleGV := inputRes.GroupVersion()
 | 
						|
		if resource.Group != "" && resource.Version != "" {
 | 
						|
			scaleGV = schema.GroupVersion{
 | 
						|
				Group:   resource.Group,
 | 
						|
				Version: resource.Version,
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return scaleGV.WithKind(resource.Kind), nil
 | 
						|
	}
 | 
						|
 | 
						|
	return schema.GroupVersionKind{}, fmt.Errorf("could not find scale subresource for %s in discovery information", inputRes.String())
 | 
						|
}
 | 
						|
 | 
						|
// cachedScaleKindResolver is a ScaleKindResolver that caches results
 | 
						|
// from another ScaleKindResolver, re-fetching on cache misses.
 | 
						|
type cachedScaleKindResolver struct {
 | 
						|
	base ScaleKindResolver
 | 
						|
 | 
						|
	cache map[schema.GroupVersionResource]schema.GroupVersionKind
 | 
						|
	mu    sync.RWMutex
 | 
						|
}
 | 
						|
 | 
						|
func (r *cachedScaleKindResolver) ScaleForResource(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
 | 
						|
	r.mu.RLock()
 | 
						|
	gvk, isCached := r.cache[resource]
 | 
						|
	r.mu.RUnlock()
 | 
						|
	if isCached {
 | 
						|
		return gvk, nil
 | 
						|
	}
 | 
						|
 | 
						|
	// we could have multiple fetches of the same resources, but that's probably
 | 
						|
	// better than limiting to only one reader at once (mu.Mutex),
 | 
						|
	// or blocking checks for other resources while we fetch
 | 
						|
	// (mu.Lock before fetch).
 | 
						|
	gvk, err := r.base.ScaleForResource(resource)
 | 
						|
	if err != nil {
 | 
						|
		return schema.GroupVersionKind{}, err
 | 
						|
	}
 | 
						|
 | 
						|
	r.mu.Lock()
 | 
						|
	defer r.mu.Unlock()
 | 
						|
	r.cache[resource] = gvk
 | 
						|
 | 
						|
	return gvk, nil
 | 
						|
}
 | 
						|
 | 
						|
// NewDiscoveryScaleKindResolver creates a new ScaleKindResolver which uses information from the given
 | 
						|
// disovery client to resolve the correct Scale GroupVersionKind for different resources.
 | 
						|
func NewDiscoveryScaleKindResolver(client discovery.ServerResourcesInterface) ScaleKindResolver {
 | 
						|
	base := &discoveryScaleResolver{
 | 
						|
		discoveryClient: client,
 | 
						|
	}
 | 
						|
 | 
						|
	return &cachedScaleKindResolver{
 | 
						|
		base:  base,
 | 
						|
		cache: make(map[schema.GroupVersionResource]schema.GroupVersionKind),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ScaleConverter knows how to convert between external scale versions.
 | 
						|
type ScaleConverter struct {
 | 
						|
	scheme            *runtime.Scheme
 | 
						|
	codecs            serializer.CodecFactory
 | 
						|
	internalVersioner runtime.GroupVersioner
 | 
						|
}
 | 
						|
 | 
						|
// NewScaleConverter creates a new ScaleConverter for converting between
 | 
						|
// Scales in autoscaling/v1 and extensions/v1beta1.
 | 
						|
func NewScaleConverter() *ScaleConverter {
 | 
						|
	scheme := runtime.NewScheme()
 | 
						|
	scaleautoscaling.AddToScheme(scheme)
 | 
						|
	scalescheme.AddToScheme(scheme)
 | 
						|
	scaleext.AddToScheme(scheme)
 | 
						|
	scaleextint.AddToScheme(scheme)
 | 
						|
	scaleappsint.AddToScheme(scheme)
 | 
						|
	scaleappsv1beta1.AddToScheme(scheme)
 | 
						|
	scaleappsv1beta2.AddToScheme(scheme)
 | 
						|
 | 
						|
	return &ScaleConverter{
 | 
						|
		scheme: scheme,
 | 
						|
		codecs: serializer.NewCodecFactory(scheme),
 | 
						|
		internalVersioner: runtime.NewMultiGroupVersioner(
 | 
						|
			scalescheme.SchemeGroupVersion,
 | 
						|
			schema.GroupKind{Group: scaleext.GroupName, Kind: "Scale"},
 | 
						|
			schema.GroupKind{Group: scaleautoscaling.GroupName, Kind: "Scale"},
 | 
						|
			schema.GroupKind{Group: scaleappsv1beta1.GroupName, Kind: "Scale"},
 | 
						|
			schema.GroupKind{Group: scaleappsv1beta2.GroupName, Kind: "Scale"},
 | 
						|
		),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Scheme returns the scheme used by this scale converter.
 | 
						|
func (c *ScaleConverter) Scheme() *runtime.Scheme {
 | 
						|
	return c.scheme
 | 
						|
}
 | 
						|
 | 
						|
func (c *ScaleConverter) Codecs() serializer.CodecFactory {
 | 
						|
	return c.codecs
 | 
						|
}
 | 
						|
 | 
						|
func (c *ScaleConverter) ScaleVersions() []schema.GroupVersion {
 | 
						|
	return []schema.GroupVersion{
 | 
						|
		scaleautoscaling.SchemeGroupVersion,
 | 
						|
		scalescheme.SchemeGroupVersion,
 | 
						|
		scaleext.SchemeGroupVersion,
 | 
						|
		scaleextint.SchemeGroupVersion,
 | 
						|
		scaleappsint.SchemeGroupVersion,
 | 
						|
		scaleappsv1beta1.SchemeGroupVersion,
 | 
						|
		scaleappsv1beta2.SchemeGroupVersion,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ConvertToVersion converts the given *external* input object to the given output *external* output group-version.
 | 
						|
func (c *ScaleConverter) ConvertToVersion(in runtime.Object, outVersion schema.GroupVersion) (runtime.Object, error) {
 | 
						|
	scaleInt, err := c.scheme.ConvertToVersion(in, c.internalVersioner)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return c.scheme.ConvertToVersion(scaleInt, outVersion)
 | 
						|
}
 |