git subrepo clone (merge) https://github.com/kubernetes-incubator/metrics-server.git metrics-server
subrepo:
subdir: "metrics-server"
merged: "92d8412"
upstream:
origin: "https://github.com/kubernetes-incubator/metrics-server.git"
branch: "master"
commit: "92d8412"
git-subrepo:
version: "0.4.0"
origin: "???"
commit: "???"
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/storage/storage_factory.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/storage/storage_factory.go
new file mode 100644
index 0000000..50c0682
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/storage/storage_factory.go
@@ -0,0 +1,350 @@
+/*
+Copyright 2016 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 storage
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "io/ioutil"
+ "strings"
+
+ "github.com/golang/glog"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apiserver/pkg/features"
+ "k8s.io/apiserver/pkg/storage/storagebackend"
+ "k8s.io/apiserver/pkg/storage/value"
+ utilfeature "k8s.io/apiserver/pkg/util/feature"
+)
+
+// Backend describes the storage servers, the information here should be enough
+// for health validations.
+type Backend struct {
+ // the url of storage backend like: https://etcd.domain:2379
+ Server string
+ // the required tls config
+ TLSConfig *tls.Config
+}
+
+// StorageFactory is the interface to locate the storage for a given GroupResource
+type StorageFactory interface {
+ // New finds the storage destination for the given group and resource. It will
+ // return an error if the group has no storage destination configured.
+ NewConfig(groupResource schema.GroupResource) (*storagebackend.Config, error)
+
+ // ResourcePrefix returns the overridden resource prefix for the GroupResource
+ // This allows for cohabitation of resources with different native types and provides
+ // centralized control over the shape of etcd directories
+ ResourcePrefix(groupResource schema.GroupResource) string
+
+ // Backends gets all backends for all registered storage destinations.
+ // Used for getting all instances for health validations.
+ Backends() []Backend
+}
+
+// DefaultStorageFactory takes a GroupResource and returns back its storage interface. This result includes:
+// 1. Merged etcd config, including: auth, server locations, prefixes
+// 2. Resource encodings for storage: group,version,kind to store as
+// 3. Cohabitating default: some resources like hpa are exposed through multiple APIs. They must agree on 1 and 2
+type DefaultStorageFactory struct {
+ // StorageConfig describes how to create a storage backend in general.
+ // Its authentication information will be used for every storage.Interface returned.
+ StorageConfig storagebackend.Config
+
+ Overrides map[schema.GroupResource]groupResourceOverrides
+
+ DefaultResourcePrefixes map[schema.GroupResource]string
+
+ // DefaultMediaType is the media type used to store resources. If it is not set, "application/json" is used.
+ DefaultMediaType string
+
+ // DefaultSerializer is used to create encoders and decoders for the storage.Interface.
+ DefaultSerializer runtime.StorageSerializer
+
+ // ResourceEncodingConfig describes how to encode a particular GroupVersionResource
+ ResourceEncodingConfig ResourceEncodingConfig
+
+ // APIResourceConfigSource indicates whether the *storage* is enabled, NOT the API
+ // This is discrete from resource enablement because those are separate concerns. How this source is configured
+ // is left to the caller.
+ APIResourceConfigSource APIResourceConfigSource
+
+ // newStorageCodecFn exists to be overwritten for unit testing.
+ newStorageCodecFn func(opts StorageCodecConfig) (codec runtime.Codec, err error)
+}
+
+type groupResourceOverrides struct {
+ // etcdLocation contains the list of "special" locations that are used for particular GroupResources
+ // These are merged on top of the StorageConfig when requesting the storage.Interface for a given GroupResource
+ etcdLocation []string
+ // etcdPrefix is the base location for a GroupResource.
+ etcdPrefix string
+ // etcdResourcePrefix is the location to use to store a particular type under the `etcdPrefix` location
+ // If empty, the default mapping is used. If the default mapping doesn't contain an entry, it will use
+ // the ToLowered name of the resource, not including the group.
+ etcdResourcePrefix string
+ // mediaType is the desired serializer to choose. If empty, the default is chosen.
+ mediaType string
+ // serializer contains the list of "special" serializers for a GroupResource. Resource=* means for the entire group
+ serializer runtime.StorageSerializer
+ // cohabitatingResources keeps track of which resources must be stored together. This happens when we have multiple ways
+ // of exposing one set of concepts. autoscaling.HPA and extensions.HPA as a for instance
+ // The order of the slice matters! It is the priority order of lookup for finding a storage location
+ cohabitatingResources []schema.GroupResource
+ // encoderDecoratorFn is optional and may wrap the provided encoder prior to being serialized.
+ encoderDecoratorFn func(runtime.Encoder) runtime.Encoder
+ // decoderDecoratorFn is optional and may wrap the provided decoders (can add new decoders). The order of
+ // returned decoders will be priority for attempt to decode.
+ decoderDecoratorFn func([]runtime.Decoder) []runtime.Decoder
+ // transformer is optional and shall encrypt that resource at rest.
+ transformer value.Transformer
+ // disablePaging will prevent paging on the provided resource.
+ disablePaging bool
+}
+
+// Apply overrides the provided config and options if the override has a value in that position
+func (o groupResourceOverrides) Apply(config *storagebackend.Config, options *StorageCodecConfig) {
+ if len(o.etcdLocation) > 0 {
+ config.ServerList = o.etcdLocation
+ }
+ if len(o.etcdPrefix) > 0 {
+ config.Prefix = o.etcdPrefix
+ }
+
+ if len(o.mediaType) > 0 {
+ options.StorageMediaType = o.mediaType
+ }
+ if o.serializer != nil {
+ options.StorageSerializer = o.serializer
+ }
+ if o.encoderDecoratorFn != nil {
+ options.EncoderDecoratorFn = o.encoderDecoratorFn
+ }
+ if o.decoderDecoratorFn != nil {
+ options.DecoderDecoratorFn = o.decoderDecoratorFn
+ }
+ if o.transformer != nil {
+ config.Transformer = o.transformer
+ }
+ if o.disablePaging {
+ config.Paging = false
+ }
+}
+
+var _ StorageFactory = &DefaultStorageFactory{}
+
+const AllResources = "*"
+
+func NewDefaultStorageFactory(
+ config storagebackend.Config,
+ defaultMediaType string,
+ defaultSerializer runtime.StorageSerializer,
+ resourceEncodingConfig ResourceEncodingConfig,
+ resourceConfig APIResourceConfigSource,
+ specialDefaultResourcePrefixes map[schema.GroupResource]string,
+) *DefaultStorageFactory {
+ config.Paging = utilfeature.DefaultFeatureGate.Enabled(features.APIListChunking)
+ if len(defaultMediaType) == 0 {
+ defaultMediaType = runtime.ContentTypeJSON
+ }
+ return &DefaultStorageFactory{
+ StorageConfig: config,
+ Overrides: map[schema.GroupResource]groupResourceOverrides{},
+ DefaultMediaType: defaultMediaType,
+ DefaultSerializer: defaultSerializer,
+ ResourceEncodingConfig: resourceEncodingConfig,
+ APIResourceConfigSource: resourceConfig,
+ DefaultResourcePrefixes: specialDefaultResourcePrefixes,
+
+ newStorageCodecFn: NewStorageCodec,
+ }
+}
+
+func (s *DefaultStorageFactory) SetEtcdLocation(groupResource schema.GroupResource, location []string) {
+ overrides := s.Overrides[groupResource]
+ overrides.etcdLocation = location
+ s.Overrides[groupResource] = overrides
+}
+
+func (s *DefaultStorageFactory) SetEtcdPrefix(groupResource schema.GroupResource, prefix string) {
+ overrides := s.Overrides[groupResource]
+ overrides.etcdPrefix = prefix
+ s.Overrides[groupResource] = overrides
+}
+
+// SetDisableAPIListChunking allows a specific resource to disable paging at the storage layer, to prevent
+// exposure of key names in continuations. This may be overridden by feature gates.
+func (s *DefaultStorageFactory) SetDisableAPIListChunking(groupResource schema.GroupResource) {
+ overrides := s.Overrides[groupResource]
+ overrides.disablePaging = true
+ s.Overrides[groupResource] = overrides
+}
+
+// SetResourceEtcdPrefix sets the prefix for a resource, but not the base-dir. You'll end up in `etcdPrefix/resourceEtcdPrefix`.
+func (s *DefaultStorageFactory) SetResourceEtcdPrefix(groupResource schema.GroupResource, prefix string) {
+ overrides := s.Overrides[groupResource]
+ overrides.etcdResourcePrefix = prefix
+ s.Overrides[groupResource] = overrides
+}
+
+func (s *DefaultStorageFactory) SetSerializer(groupResource schema.GroupResource, mediaType string, serializer runtime.StorageSerializer) {
+ overrides := s.Overrides[groupResource]
+ overrides.mediaType = mediaType
+ overrides.serializer = serializer
+ s.Overrides[groupResource] = overrides
+}
+
+func (s *DefaultStorageFactory) SetTransformer(groupResource schema.GroupResource, transformer value.Transformer) {
+ overrides := s.Overrides[groupResource]
+ overrides.transformer = transformer
+ s.Overrides[groupResource] = overrides
+}
+
+// AddCohabitatingResources links resources together the order of the slice matters! its the priority order of lookup for finding a storage location
+func (s *DefaultStorageFactory) AddCohabitatingResources(groupResources ...schema.GroupResource) {
+ for _, groupResource := range groupResources {
+ overrides := s.Overrides[groupResource]
+ overrides.cohabitatingResources = groupResources
+ s.Overrides[groupResource] = overrides
+ }
+}
+
+func (s *DefaultStorageFactory) AddSerializationChains(encoderDecoratorFn func(runtime.Encoder) runtime.Encoder, decoderDecoratorFn func([]runtime.Decoder) []runtime.Decoder, groupResources ...schema.GroupResource) {
+ for _, groupResource := range groupResources {
+ overrides := s.Overrides[groupResource]
+ overrides.encoderDecoratorFn = encoderDecoratorFn
+ overrides.decoderDecoratorFn = decoderDecoratorFn
+ s.Overrides[groupResource] = overrides
+ }
+}
+
+func getAllResourcesAlias(resource schema.GroupResource) schema.GroupResource {
+ return schema.GroupResource{Group: resource.Group, Resource: AllResources}
+}
+
+func (s *DefaultStorageFactory) getStorageGroupResource(groupResource schema.GroupResource) schema.GroupResource {
+ for _, potentialStorageResource := range s.Overrides[groupResource].cohabitatingResources {
+ if s.APIResourceConfigSource.AnyVersionForGroupEnabled(potentialStorageResource.Group) {
+ return potentialStorageResource
+ }
+ }
+
+ return groupResource
+}
+
+// New finds the storage destination for the given group and resource. It will
+// return an error if the group has no storage destination configured.
+func (s *DefaultStorageFactory) NewConfig(groupResource schema.GroupResource) (*storagebackend.Config, error) {
+ chosenStorageResource := s.getStorageGroupResource(groupResource)
+
+ // operate on copy
+ storageConfig := s.StorageConfig
+ codecConfig := StorageCodecConfig{
+ StorageMediaType: s.DefaultMediaType,
+ StorageSerializer: s.DefaultSerializer,
+ }
+
+ if override, ok := s.Overrides[getAllResourcesAlias(chosenStorageResource)]; ok {
+ override.Apply(&storageConfig, &codecConfig)
+ }
+ if override, ok := s.Overrides[chosenStorageResource]; ok {
+ override.Apply(&storageConfig, &codecConfig)
+ }
+
+ var err error
+ codecConfig.StorageVersion, err = s.ResourceEncodingConfig.StorageEncodingFor(chosenStorageResource)
+ if err != nil {
+ return nil, err
+ }
+ codecConfig.MemoryVersion, err = s.ResourceEncodingConfig.InMemoryEncodingFor(groupResource)
+ if err != nil {
+ return nil, err
+ }
+ codecConfig.Config = storageConfig
+
+ storageConfig.Codec, err = s.newStorageCodecFn(codecConfig)
+ if err != nil {
+ return nil, err
+ }
+ glog.V(3).Infof("storing %v in %v, reading as %v from %#v", groupResource, codecConfig.StorageVersion, codecConfig.MemoryVersion, codecConfig.Config)
+
+ return &storageConfig, nil
+}
+
+// Backends returns all backends for all registered storage destinations.
+// Used for getting all instances for health validations.
+func (s *DefaultStorageFactory) Backends() []Backend {
+ servers := sets.NewString(s.StorageConfig.ServerList...)
+
+ for _, overrides := range s.Overrides {
+ servers.Insert(overrides.etcdLocation...)
+ }
+
+ tlsConfig := &tls.Config{
+ InsecureSkipVerify: true,
+ }
+ if len(s.StorageConfig.CertFile) > 0 && len(s.StorageConfig.KeyFile) > 0 {
+ cert, err := tls.LoadX509KeyPair(s.StorageConfig.CertFile, s.StorageConfig.KeyFile)
+ if err != nil {
+ glog.Errorf("failed to load key pair while getting backends: %s", err)
+ } else {
+ tlsConfig.Certificates = []tls.Certificate{cert}
+ }
+ }
+ if len(s.StorageConfig.CAFile) > 0 {
+ if caCert, err := ioutil.ReadFile(s.StorageConfig.CAFile); err != nil {
+ glog.Errorf("failed to read ca file while getting backends: %s", err)
+ } else {
+ caPool := x509.NewCertPool()
+ caPool.AppendCertsFromPEM(caCert)
+ tlsConfig.RootCAs = caPool
+ tlsConfig.InsecureSkipVerify = false
+ }
+ }
+
+ backends := []Backend{}
+ for server := range servers {
+ backends = append(backends, Backend{
+ Server: server,
+ // We can't share TLSConfig across different backends to avoid races.
+ // For more details see: http://pr.k8s.io/59338
+ TLSConfig: tlsConfig.Clone(),
+ })
+ }
+ return backends
+}
+
+func (s *DefaultStorageFactory) ResourcePrefix(groupResource schema.GroupResource) string {
+ chosenStorageResource := s.getStorageGroupResource(groupResource)
+ groupOverride := s.Overrides[getAllResourcesAlias(chosenStorageResource)]
+ exactResourceOverride := s.Overrides[chosenStorageResource]
+
+ etcdResourcePrefix := s.DefaultResourcePrefixes[chosenStorageResource]
+ if len(groupOverride.etcdResourcePrefix) > 0 {
+ etcdResourcePrefix = groupOverride.etcdResourcePrefix
+ }
+ if len(exactResourceOverride.etcdResourcePrefix) > 0 {
+ etcdResourcePrefix = exactResourceOverride.etcdResourcePrefix
+ }
+ if len(etcdResourcePrefix) == 0 {
+ etcdResourcePrefix = strings.ToLower(chosenStorageResource.Resource)
+ }
+
+ return etcdResourcePrefix
+}