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/genericapiserver.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
new file mode 100644
index 0000000..9beba73
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
@@ -0,0 +1,445 @@
+/*
+Copyright 2014 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 server
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+
+ systemd "github.com/coreos/go-systemd/daemon"
+ "github.com/emicklei/go-restful-swagger12"
+ "github.com/golang/glog"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/apimachinery/pkg/util/sets"
+ utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup"
+ "k8s.io/apiserver/pkg/admission"
+ "k8s.io/apiserver/pkg/audit"
+ genericapi "k8s.io/apiserver/pkg/endpoints"
+ "k8s.io/apiserver/pkg/endpoints/discovery"
+ "k8s.io/apiserver/pkg/registry/rest"
+ "k8s.io/apiserver/pkg/server/healthz"
+ "k8s.io/apiserver/pkg/server/routes"
+ restclient "k8s.io/client-go/rest"
+ openapicommon "k8s.io/kube-openapi/pkg/common"
+)
+
+// Info about an API group.
+type APIGroupInfo struct {
+ PrioritizedVersions []schema.GroupVersion
+ // Info about the resources in this group. It's a map from version to resource to the storage.
+ VersionedResourcesStorageMap map[string]map[string]rest.Storage
+ // OptionsExternalVersion controls the APIVersion used for common objects in the
+ // schema like api.Status, api.DeleteOptions, and metav1.ListOptions. Other implementors may
+ // define a version "v1beta1" but want to use the Kubernetes "v1" internal objects.
+ // If nil, defaults to groupMeta.GroupVersion.
+ // TODO: Remove this when https://github.com/kubernetes/kubernetes/issues/19018 is fixed.
+ OptionsExternalVersion *schema.GroupVersion
+ // MetaGroupVersion defaults to "meta.k8s.io/v1" and is the scheme group version used to decode
+ // common API implementations like ListOptions. Future changes will allow this to vary by group
+ // version (for when the inevitable meta/v2 group emerges).
+ MetaGroupVersion *schema.GroupVersion
+
+ // Scheme includes all of the types used by this group and how to convert between them (or
+ // to convert objects from outside of this group that are accepted in this API).
+ // TODO: replace with interfaces
+ Scheme *runtime.Scheme
+ // NegotiatedSerializer controls how this group encodes and decodes data
+ NegotiatedSerializer runtime.NegotiatedSerializer
+ // ParameterCodec performs conversions for query parameters passed to API calls
+ ParameterCodec runtime.ParameterCodec
+}
+
+// GenericAPIServer contains state for a Kubernetes cluster api server.
+type GenericAPIServer struct {
+ // discoveryAddresses is used to build cluster IPs for discovery.
+ discoveryAddresses discovery.Addresses
+
+ // LoopbackClientConfig is a config for a privileged loopback connection to the API server
+ LoopbackClientConfig *restclient.Config
+
+ // minRequestTimeout is how short the request timeout can be. This is used to build the RESTHandler
+ minRequestTimeout time.Duration
+
+ // ShutdownTimeout is the timeout used for server shutdown. This specifies the timeout before server
+ // gracefully shutdown returns.
+ ShutdownTimeout time.Duration
+
+ // legacyAPIGroupPrefixes is used to set up URL parsing for authorization and for validating requests
+ // to InstallLegacyAPIGroup
+ legacyAPIGroupPrefixes sets.String
+
+ // admissionControl is used to build the RESTStorage that backs an API Group.
+ admissionControl admission.Interface
+
+ // SecureServingInfo holds configuration of the TLS server.
+ SecureServingInfo *SecureServingInfo
+
+ // ExternalAddress is the address (hostname or IP and port) that should be used in
+ // external (public internet) URLs for this GenericAPIServer.
+ ExternalAddress string
+
+ // Serializer controls how common API objects not in a group/version prefix are serialized for this server.
+ // Individual APIGroups may define their own serializers.
+ Serializer runtime.NegotiatedSerializer
+
+ // "Outputs"
+ // Handler holds the handlers being used by this API server
+ Handler *APIServerHandler
+
+ // listedPathProvider is a lister which provides the set of paths to show at /
+ listedPathProvider routes.ListedPathProvider
+
+ // DiscoveryGroupManager serves /apis
+ DiscoveryGroupManager discovery.GroupManager
+
+ // Enable swagger and/or OpenAPI if these configs are non-nil.
+ swaggerConfig *swagger.Config
+ openAPIConfig *openapicommon.Config
+
+ // PostStartHooks are each called after the server has started listening, in a separate go func for each
+ // with no guarantee of ordering between them. The map key is a name used for error reporting.
+ // It may kill the process with a panic if it wishes to by returning an error.
+ postStartHookLock sync.Mutex
+ postStartHooks map[string]postStartHookEntry
+ postStartHooksCalled bool
+ disabledPostStartHooks sets.String
+
+ preShutdownHookLock sync.Mutex
+ preShutdownHooks map[string]preShutdownHookEntry
+ preShutdownHooksCalled bool
+
+ // healthz checks
+ healthzLock sync.Mutex
+ healthzChecks []healthz.HealthzChecker
+ healthzCreated bool
+
+ // auditing. The backend is started after the server starts listening.
+ AuditBackend audit.Backend
+
+ // enableAPIResponseCompression indicates whether API Responses should support compression
+ // if the client requests it via Accept-Encoding
+ enableAPIResponseCompression bool
+
+ // delegationTarget is the next delegate in the chain. This is never nil.
+ delegationTarget DelegationTarget
+
+ // HandlerChainWaitGroup allows you to wait for all chain handlers finish after the server shutdown.
+ HandlerChainWaitGroup *utilwaitgroup.SafeWaitGroup
+}
+
+// DelegationTarget is an interface which allows for composition of API servers with top level handling that works
+// as expected.
+type DelegationTarget interface {
+ // UnprotectedHandler returns a handler that is NOT protected by a normal chain
+ UnprotectedHandler() http.Handler
+
+ // PostStartHooks returns the post-start hooks that need to be combined
+ PostStartHooks() map[string]postStartHookEntry
+
+ // PreShutdownHooks returns the pre-stop hooks that need to be combined
+ PreShutdownHooks() map[string]preShutdownHookEntry
+
+ // HealthzChecks returns the healthz checks that need to be combined
+ HealthzChecks() []healthz.HealthzChecker
+
+ // ListedPaths returns the paths for supporting an index
+ ListedPaths() []string
+
+ // NextDelegate returns the next delegationTarget in the chain of delegations
+ NextDelegate() DelegationTarget
+}
+
+func (s *GenericAPIServer) UnprotectedHandler() http.Handler {
+ // when we delegate, we need the server we're delegating to choose whether or not to use gorestful
+ return s.Handler.Director
+}
+func (s *GenericAPIServer) PostStartHooks() map[string]postStartHookEntry {
+ return s.postStartHooks
+}
+func (s *GenericAPIServer) PreShutdownHooks() map[string]preShutdownHookEntry {
+ return s.preShutdownHooks
+}
+func (s *GenericAPIServer) HealthzChecks() []healthz.HealthzChecker {
+ return s.healthzChecks
+}
+func (s *GenericAPIServer) ListedPaths() []string {
+ return s.listedPathProvider.ListedPaths()
+}
+
+func (s *GenericAPIServer) NextDelegate() DelegationTarget {
+ return s.delegationTarget
+}
+
+type emptyDelegate struct {
+}
+
+func NewEmptyDelegate() DelegationTarget {
+ return emptyDelegate{}
+}
+
+func (s emptyDelegate) UnprotectedHandler() http.Handler {
+ return nil
+}
+func (s emptyDelegate) PostStartHooks() map[string]postStartHookEntry {
+ return map[string]postStartHookEntry{}
+}
+func (s emptyDelegate) PreShutdownHooks() map[string]preShutdownHookEntry {
+ return map[string]preShutdownHookEntry{}
+}
+func (s emptyDelegate) HealthzChecks() []healthz.HealthzChecker {
+ return []healthz.HealthzChecker{}
+}
+func (s emptyDelegate) ListedPaths() []string {
+ return []string{}
+}
+func (s emptyDelegate) NextDelegate() DelegationTarget {
+ return nil
+}
+
+// preparedGenericAPIServer is a private wrapper that enforces a call of PrepareRun() before Run can be invoked.
+type preparedGenericAPIServer struct {
+ *GenericAPIServer
+}
+
+// PrepareRun does post API installation setup steps.
+func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
+ if s.swaggerConfig != nil {
+ routes.Swagger{Config: s.swaggerConfig}.Install(s.Handler.GoRestfulContainer)
+ }
+ if s.openAPIConfig != nil {
+ routes.OpenAPI{
+ Config: s.openAPIConfig,
+ }.Install(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
+ }
+
+ s.installHealthz()
+
+ // Register audit backend preShutdownHook.
+ if s.AuditBackend != nil {
+ s.AddPreShutdownHook("audit-backend", func() error {
+ s.AuditBackend.Shutdown()
+ return nil
+ })
+ }
+
+ return preparedGenericAPIServer{s}
+}
+
+// Run spawns the secure http server. It only returns if stopCh is closed
+// or the secure port cannot be listened on initially.
+func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
+ err := s.NonBlockingRun(stopCh)
+ if err != nil {
+ return err
+ }
+
+ <-stopCh
+
+ err = s.RunPreShutdownHooks()
+ if err != nil {
+ return err
+ }
+
+ // Wait for all requests to finish, which are bounded by the RequestTimeout variable.
+ s.HandlerChainWaitGroup.Wait()
+
+ return nil
+}
+
+// NonBlockingRun spawns the secure http server. An error is
+// returned if the secure port cannot be listened on.
+func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error {
+ // Use an stop channel to allow graceful shutdown without dropping audit events
+ // after http server shutdown.
+ auditStopCh := make(chan struct{})
+
+ // Start the audit backend before any request comes in. This means we must call Backend.Run
+ // before http server start serving. Otherwise the Backend.ProcessEvents call might block.
+ if s.AuditBackend != nil {
+ if err := s.AuditBackend.Run(auditStopCh); err != nil {
+ return fmt.Errorf("failed to run the audit backend: %v", err)
+ }
+ }
+
+ // Use an internal stop channel to allow cleanup of the listeners on error.
+ internalStopCh := make(chan struct{})
+
+ if s.SecureServingInfo != nil && s.Handler != nil {
+ if err := s.SecureServingInfo.Serve(s.Handler, s.ShutdownTimeout, internalStopCh); err != nil {
+ close(internalStopCh)
+ return err
+ }
+ }
+
+ // Now that listener have bound successfully, it is the
+ // responsibility of the caller to close the provided channel to
+ // ensure cleanup.
+ go func() {
+ <-stopCh
+ close(internalStopCh)
+ s.HandlerChainWaitGroup.Wait()
+ close(auditStopCh)
+ }()
+
+ s.RunPostStartHooks(stopCh)
+
+ if _, err := systemd.SdNotify(true, "READY=1\n"); err != nil {
+ glog.Errorf("Unable to send systemd daemon successful start message: %v\n", err)
+ }
+
+ return nil
+}
+
+// installAPIResources is a private method for installing the REST storage backing each api groupversionresource
+func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
+ for _, groupVersion := range apiGroupInfo.PrioritizedVersions {
+ if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 {
+ glog.Warningf("Skipping API %v because it has no resources.", groupVersion)
+ continue
+ }
+
+ apiGroupVersion := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix)
+ if apiGroupInfo.OptionsExternalVersion != nil {
+ apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion
+ }
+
+ if err := apiGroupVersion.InstallREST(s.Handler.GoRestfulContainer); err != nil {
+ return fmt.Errorf("unable to setup API %v: %v", apiGroupInfo, err)
+ }
+ }
+
+ return nil
+}
+
+func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
+ if !s.legacyAPIGroupPrefixes.Has(apiPrefix) {
+ return fmt.Errorf("%q is not in the allowed legacy API prefixes: %v", apiPrefix, s.legacyAPIGroupPrefixes.List())
+ }
+ if err := s.installAPIResources(apiPrefix, apiGroupInfo); err != nil {
+ return err
+ }
+
+ // setup discovery
+ apiVersions := []string{}
+ for _, groupVersion := range apiGroupInfo.PrioritizedVersions {
+ apiVersions = append(apiVersions, groupVersion.Version)
+ }
+ // Install the version handler.
+ // Add a handler at /<apiPrefix> to enumerate the supported api versions.
+ s.Handler.GoRestfulContainer.Add(discovery.NewLegacyRootAPIHandler(s.discoveryAddresses, s.Serializer, apiPrefix, apiVersions).WebService())
+
+ return nil
+}
+
+// Exposes the given api group in the API.
+func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error {
+ // Do not register empty group or empty version. Doing so claims /apis/ for the wrong entity to be returned.
+ // Catching these here places the error much closer to its origin
+ if len(apiGroupInfo.PrioritizedVersions[0].Group) == 0 {
+ return fmt.Errorf("cannot register handler with an empty group for %#v", *apiGroupInfo)
+ }
+ if len(apiGroupInfo.PrioritizedVersions[0].Version) == 0 {
+ return fmt.Errorf("cannot register handler with an empty version for %#v", *apiGroupInfo)
+ }
+
+ if err := s.installAPIResources(APIGroupPrefix, apiGroupInfo); err != nil {
+ return err
+ }
+
+ // setup discovery
+ // Install the version handler.
+ // Add a handler at /apis/<groupName> to enumerate all versions supported by this group.
+ apiVersionsForDiscovery := []metav1.GroupVersionForDiscovery{}
+ for _, groupVersion := range apiGroupInfo.PrioritizedVersions {
+ // Check the config to make sure that we elide versions that don't have any resources
+ if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 {
+ continue
+ }
+ apiVersionsForDiscovery = append(apiVersionsForDiscovery, metav1.GroupVersionForDiscovery{
+ GroupVersion: groupVersion.String(),
+ Version: groupVersion.Version,
+ })
+ }
+ preferredVersionForDiscovery := metav1.GroupVersionForDiscovery{
+ GroupVersion: apiGroupInfo.PrioritizedVersions[0].String(),
+ Version: apiGroupInfo.PrioritizedVersions[0].Version,
+ }
+ apiGroup := metav1.APIGroup{
+ Name: apiGroupInfo.PrioritizedVersions[0].Group,
+ Versions: apiVersionsForDiscovery,
+ PreferredVersion: preferredVersionForDiscovery,
+ }
+
+ s.DiscoveryGroupManager.AddGroup(apiGroup)
+ s.Handler.GoRestfulContainer.Add(discovery.NewAPIGroupHandler(s.Serializer, apiGroup).WebService())
+
+ return nil
+}
+
+func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion schema.GroupVersion, apiPrefix string) *genericapi.APIGroupVersion {
+ storage := make(map[string]rest.Storage)
+ for k, v := range apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version] {
+ storage[strings.ToLower(k)] = v
+ }
+ version := s.newAPIGroupVersion(apiGroupInfo, groupVersion)
+ version.Root = apiPrefix
+ version.Storage = storage
+ return version
+}
+
+func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion schema.GroupVersion) *genericapi.APIGroupVersion {
+ return &genericapi.APIGroupVersion{
+ GroupVersion: groupVersion,
+ MetaGroupVersion: apiGroupInfo.MetaGroupVersion,
+
+ ParameterCodec: apiGroupInfo.ParameterCodec,
+ Serializer: apiGroupInfo.NegotiatedSerializer,
+ Creater: apiGroupInfo.Scheme,
+ Convertor: apiGroupInfo.Scheme,
+ UnsafeConvertor: runtime.UnsafeObjectConvertor(apiGroupInfo.Scheme),
+ Defaulter: apiGroupInfo.Scheme,
+ Typer: apiGroupInfo.Scheme,
+ Linker: runtime.SelfLinker(meta.NewAccessor()),
+
+ Admit: s.admissionControl,
+ MinRequestTimeout: s.minRequestTimeout,
+ EnableAPIResponseCompression: s.enableAPIResponseCompression,
+ OpenAPIConfig: s.openAPIConfig,
+ }
+}
+
+// NewDefaultAPIGroupInfo returns an APIGroupInfo stubbed with "normal" values
+// exposed for easier composition from other packages
+func NewDefaultAPIGroupInfo(group string, scheme *runtime.Scheme, parameterCodec runtime.ParameterCodec, codecs serializer.CodecFactory) APIGroupInfo {
+ return APIGroupInfo{
+ PrioritizedVersions: scheme.PrioritizedVersionsForGroup(group),
+ VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
+ // TODO unhardcode this. It was hardcoded before, but we need to re-evaluate
+ OptionsExternalVersion: &schema.GroupVersion{Version: "v1"},
+ Scheme: scheme,
+ ParameterCodec: parameterCodec,
+ NegotiatedSerializer: codecs,
+ }
+}