...

Source file src/k8s.io/client-go/scale/util.go

Documentation: k8s.io/client-go/scale

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package scale
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"sync"
    23  
    24  	"k8s.io/apimachinery/pkg/api/meta"
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	serializer "k8s.io/apimachinery/pkg/runtime/serializer"
    28  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    29  	"k8s.io/client-go/discovery"
    30  	scalescheme "k8s.io/client-go/scale/scheme"
    31  	scaleappsint "k8s.io/client-go/scale/scheme/appsint"
    32  	scaleappsv1beta1 "k8s.io/client-go/scale/scheme/appsv1beta1"
    33  	scaleappsv1beta2 "k8s.io/client-go/scale/scheme/appsv1beta2"
    34  	scaleautoscaling "k8s.io/client-go/scale/scheme/autoscalingv1"
    35  	scaleextint "k8s.io/client-go/scale/scheme/extensionsint"
    36  	scaleext "k8s.io/client-go/scale/scheme/extensionsv1beta1"
    37  )
    38  
    39  // PreferredResourceMapper determines the preferred version of a resource to scale
    40  type PreferredResourceMapper interface {
    41  	// ResourceFor takes a partial resource and returns the preferred resource.
    42  	ResourceFor(resource schema.GroupVersionResource) (preferredResource schema.GroupVersionResource, err error)
    43  }
    44  
    45  // Ensure a RESTMapper satisfies the PreferredResourceMapper interface
    46  var _ PreferredResourceMapper = meta.RESTMapper(nil)
    47  
    48  // ScaleKindResolver knows about the relationship between
    49  // resources and the GroupVersionKind of their scale subresources.
    50  type ScaleKindResolver interface {
    51  	// ScaleForResource returns the GroupVersionKind of the
    52  	// scale subresource for the given GroupVersionResource.
    53  	ScaleForResource(resource schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error)
    54  }
    55  
    56  // discoveryScaleResolver is a ScaleKindResolver that uses
    57  // a DiscoveryInterface to associate resources with their
    58  // scale-kinds
    59  type discoveryScaleResolver struct {
    60  	discoveryClient discovery.ServerResourcesInterface
    61  }
    62  
    63  func (r *discoveryScaleResolver) ScaleForResource(inputRes schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error) {
    64  	groupVerResources, err := r.discoveryClient.ServerResourcesForGroupVersion(inputRes.GroupVersion().String())
    65  	if err != nil {
    66  		return schema.GroupVersionKind{}, fmt.Errorf("unable to fetch discovery information for %s: %v", inputRes.String(), err)
    67  	}
    68  
    69  	for _, resource := range groupVerResources.APIResources {
    70  		resourceParts := strings.SplitN(resource.Name, "/", 2)
    71  		if len(resourceParts) != 2 || resourceParts[0] != inputRes.Resource || resourceParts[1] != "scale" {
    72  			// skip non-scale resources, or scales for resources that we're not looking for
    73  			continue
    74  		}
    75  
    76  		scaleGV := inputRes.GroupVersion()
    77  		if resource.Group != "" && resource.Version != "" {
    78  			scaleGV = schema.GroupVersion{
    79  				Group:   resource.Group,
    80  				Version: resource.Version,
    81  			}
    82  		}
    83  
    84  		return scaleGV.WithKind(resource.Kind), nil
    85  	}
    86  
    87  	return schema.GroupVersionKind{}, fmt.Errorf("could not find scale subresource for %s in discovery information", inputRes.String())
    88  }
    89  
    90  // cachedScaleKindResolver is a ScaleKindResolver that caches results
    91  // from another ScaleKindResolver, re-fetching on cache misses.
    92  type cachedScaleKindResolver struct {
    93  	base ScaleKindResolver
    94  
    95  	cache map[schema.GroupVersionResource]schema.GroupVersionKind
    96  	mu    sync.RWMutex
    97  }
    98  
    99  func (r *cachedScaleKindResolver) ScaleForResource(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
   100  	r.mu.RLock()
   101  	gvk, isCached := r.cache[resource]
   102  	r.mu.RUnlock()
   103  	if isCached {
   104  		return gvk, nil
   105  	}
   106  
   107  	// we could have multiple fetches of the same resources, but that's probably
   108  	// better than limiting to only one reader at once (mu.Mutex),
   109  	// or blocking checks for other resources while we fetch
   110  	// (mu.Lock before fetch).
   111  	gvk, err := r.base.ScaleForResource(resource)
   112  	if err != nil {
   113  		return schema.GroupVersionKind{}, err
   114  	}
   115  
   116  	r.mu.Lock()
   117  	defer r.mu.Unlock()
   118  	r.cache[resource] = gvk
   119  
   120  	return gvk, nil
   121  }
   122  
   123  // NewDiscoveryScaleKindResolver creates a new ScaleKindResolver which uses information from the given
   124  // disovery client to resolve the correct Scale GroupVersionKind for different resources.
   125  func NewDiscoveryScaleKindResolver(client discovery.ServerResourcesInterface) ScaleKindResolver {
   126  	base := &discoveryScaleResolver{
   127  		discoveryClient: client,
   128  	}
   129  
   130  	return &cachedScaleKindResolver{
   131  		base:  base,
   132  		cache: make(map[schema.GroupVersionResource]schema.GroupVersionKind),
   133  	}
   134  }
   135  
   136  // ScaleConverter knows how to convert between external scale versions.
   137  type ScaleConverter struct {
   138  	scheme            *runtime.Scheme
   139  	codecs            serializer.CodecFactory
   140  	internalVersioner runtime.GroupVersioner
   141  }
   142  
   143  // NewScaleConverter creates a new ScaleConverter for converting between
   144  // Scales in autoscaling/v1 and extensions/v1beta1.
   145  func NewScaleConverter() *ScaleConverter {
   146  	scheme := runtime.NewScheme()
   147  	utilruntime.Must(scaleautoscaling.AddToScheme(scheme))
   148  	utilruntime.Must(scalescheme.AddToScheme(scheme))
   149  	utilruntime.Must(scaleext.AddToScheme(scheme))
   150  	utilruntime.Must(scaleextint.AddToScheme(scheme))
   151  	utilruntime.Must(scaleappsint.AddToScheme(scheme))
   152  	utilruntime.Must(scaleappsv1beta1.AddToScheme(scheme))
   153  	utilruntime.Must(scaleappsv1beta2.AddToScheme(scheme))
   154  
   155  	return &ScaleConverter{
   156  		scheme: scheme,
   157  		codecs: serializer.NewCodecFactory(scheme),
   158  		internalVersioner: runtime.NewMultiGroupVersioner(
   159  			scalescheme.SchemeGroupVersion,
   160  			schema.GroupKind{Group: scaleext.GroupName, Kind: "Scale"},
   161  			schema.GroupKind{Group: scaleautoscaling.GroupName, Kind: "Scale"},
   162  			schema.GroupKind{Group: scaleappsv1beta1.GroupName, Kind: "Scale"},
   163  			schema.GroupKind{Group: scaleappsv1beta2.GroupName, Kind: "Scale"},
   164  		),
   165  	}
   166  }
   167  
   168  // Scheme returns the scheme used by this scale converter.
   169  func (c *ScaleConverter) Scheme() *runtime.Scheme {
   170  	return c.scheme
   171  }
   172  
   173  func (c *ScaleConverter) Codecs() serializer.CodecFactory {
   174  	return c.codecs
   175  }
   176  
   177  func (c *ScaleConverter) ScaleVersions() []schema.GroupVersion {
   178  	return []schema.GroupVersion{
   179  		scaleautoscaling.SchemeGroupVersion,
   180  		scalescheme.SchemeGroupVersion,
   181  		scaleext.SchemeGroupVersion,
   182  		scaleextint.SchemeGroupVersion,
   183  		scaleappsint.SchemeGroupVersion,
   184  		scaleappsv1beta1.SchemeGroupVersion,
   185  		scaleappsv1beta2.SchemeGroupVersion,
   186  	}
   187  }
   188  
   189  // ConvertToVersion converts the given *external* input object to the given output *external* output group-version.
   190  func (c *ScaleConverter) ConvertToVersion(in runtime.Object, outVersion schema.GroupVersion) (runtime.Object, error) {
   191  	scaleInt, err := c.scheme.ConvertToVersion(in, c.internalVersioner)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  
   196  	return c.scheme.ConvertToVersion(scaleInt, outVersion)
   197  }
   198  

View as plain text