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/options/OWNERS b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/OWNERS
new file mode 100755
index 0000000..6371177
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/OWNERS
@@ -0,0 +1,15 @@
+reviewers:
+- smarterclayton
+- wojtek-t
+- deads2k
+- liggitt
+- nikhiljindal
+- sttts
+- jlowdermilk
+- soltysh
+- dims
+- cjcullen
+- ericchiang
+- ping035627
+- xiangpengzhao
+- enj
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/admission.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/admission.go
new file mode 100644
index 0000000..37d0457
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/admission.go
@@ -0,0 +1,219 @@
+/*
+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 options
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/pflag"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apiserver/pkg/admission"
+ "k8s.io/apiserver/pkg/admission/initializer"
+ admissionmetrics "k8s.io/apiserver/pkg/admission/metrics"
+ "k8s.io/apiserver/pkg/admission/plugin/initialization"
+ "k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
+ mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating"
+ validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating"
+ apiserverapi "k8s.io/apiserver/pkg/apis/apiserver"
+ apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"
+ "k8s.io/apiserver/pkg/server"
+ "k8s.io/client-go/informers"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+)
+
+var configScheme = runtime.NewScheme()
+
+func init() {
+ apiserverapi.AddToScheme(configScheme)
+ apiserverapiv1alpha1.AddToScheme(configScheme)
+}
+
+// AdmissionOptions holds the admission options
+type AdmissionOptions struct {
+ // RecommendedPluginOrder holds an ordered list of plugin names we recommend to use by default
+ RecommendedPluginOrder []string
+ // DefaultOffPlugins is a set of plugin names that is disabled by default
+ DefaultOffPlugins sets.String
+
+ // EnablePlugins indicates plugins to be enabled passed through `--enable-admission-plugins`.
+ EnablePlugins []string
+ // DisablePlugins indicates plugins to be disabled passed through `--disable-admission-plugins`.
+ DisablePlugins []string
+ // ConfigFile is the file path with admission control configuration.
+ ConfigFile string
+ // Plugins contains all registered plugins.
+ Plugins *admission.Plugins
+}
+
+// NewAdmissionOptions creates a new instance of AdmissionOptions
+// Note:
+// In addition it calls RegisterAllAdmissionPlugins to register
+// all generic admission plugins.
+//
+// Provides the list of RecommendedPluginOrder that holds sane values
+// that can be used by servers that don't care about admission chain.
+// Servers that do care can overwrite/append that field after creation.
+func NewAdmissionOptions() *AdmissionOptions {
+ options := &AdmissionOptions{
+ Plugins: admission.NewPlugins(),
+ // This list is mix of mutating admission plugins and validating
+ // admission plugins. The apiserver always runs the validating ones
+ // after all the mutating ones, so their relative order in this list
+ // doesn't matter.
+ RecommendedPluginOrder: []string{lifecycle.PluginName, initialization.PluginName, mutatingwebhook.PluginName, validatingwebhook.PluginName},
+ DefaultOffPlugins: sets.NewString(initialization.PluginName),
+ }
+ server.RegisterAllAdmissionPlugins(options.Plugins)
+ return options
+}
+
+// AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet
+func (a *AdmissionOptions) AddFlags(fs *pflag.FlagSet) {
+ if a == nil {
+ return
+ }
+
+ fs.StringSliceVar(&a.EnablePlugins, "enable-admission-plugins", a.EnablePlugins, ""+
+ "admission plugins that should be enabled in addition to default enabled ones. "+
+ "Comma-delimited list of admission plugins: "+strings.Join(a.Plugins.Registered(), ", ")+". "+
+ "The order of plugins in this flag does not matter.")
+ fs.StringSliceVar(&a.DisablePlugins, "disable-admission-plugins", a.DisablePlugins, ""+
+ "admission plugins that should be disabled although they are in the default enabled plugins list. "+
+ "Comma-delimited list of admission plugins: "+strings.Join(a.Plugins.Registered(), ", ")+". "+
+ "The order of plugins in this flag does not matter.")
+ fs.StringVar(&a.ConfigFile, "admission-control-config-file", a.ConfigFile,
+ "File with admission control configuration.")
+}
+
+// ApplyTo adds the admission chain to the server configuration.
+// In case admission plugin names were not provided by a custer-admin they will be prepared from the recommended/default values.
+// In addition the method lazily initializes a generic plugin that is appended to the list of pluginInitializers
+// note this method uses:
+// genericconfig.Authorizer
+func (a *AdmissionOptions) ApplyTo(
+ c *server.Config,
+ informers informers.SharedInformerFactory,
+ kubeAPIServerClientConfig *rest.Config,
+ scheme *runtime.Scheme,
+ pluginInitializers ...admission.PluginInitializer,
+) error {
+ if a == nil {
+ return nil
+ }
+
+ // Admission need scheme to construct admission initializer.
+ if scheme == nil {
+ return fmt.Errorf("admission depends on a scheme, it cannot be nil")
+ }
+
+ // Admission depends on CoreAPI to set SharedInformerFactory and ClientConfig.
+ if informers == nil {
+ return fmt.Errorf("admission depends on a Kubernetes core API shared informer, it cannot be nil")
+ }
+
+ pluginNames := a.enabledPluginNames()
+
+ pluginsConfigProvider, err := admission.ReadAdmissionConfiguration(pluginNames, a.ConfigFile, configScheme)
+ if err != nil {
+ return fmt.Errorf("failed to read plugin config: %v", err)
+ }
+
+ clientset, err := kubernetes.NewForConfig(kubeAPIServerClientConfig)
+ if err != nil {
+ return err
+ }
+ genericInitializer := initializer.New(clientset, informers, c.Authorization.Authorizer, scheme)
+ initializersChain := admission.PluginInitializers{}
+ pluginInitializers = append(pluginInitializers, genericInitializer)
+ initializersChain = append(initializersChain, pluginInitializers...)
+
+ admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, admission.DecoratorFunc(admissionmetrics.WithControllerMetrics))
+ if err != nil {
+ return err
+ }
+
+ c.AdmissionControl = admissionmetrics.WithStepMetrics(admissionChain)
+ return nil
+}
+
+// Validate verifies flags passed to AdmissionOptions.
+func (a *AdmissionOptions) Validate() []error {
+ if a == nil {
+ return nil
+ }
+
+ errs := []error{}
+
+ registeredPlugins := sets.NewString(a.Plugins.Registered()...)
+ for _, name := range a.EnablePlugins {
+ if !registeredPlugins.Has(name) {
+ errs = append(errs, fmt.Errorf("enable-admission-plugins plugin %q is unknown", name))
+ }
+ }
+
+ for _, name := range a.DisablePlugins {
+ if !registeredPlugins.Has(name) {
+ errs = append(errs, fmt.Errorf("disable-admission-plugins plugin %q is unknown", name))
+ }
+ }
+
+ enablePlugins := sets.NewString(a.EnablePlugins...)
+ disablePlugins := sets.NewString(a.DisablePlugins...)
+ if len(enablePlugins.Intersection(disablePlugins).List()) > 0 {
+ errs = append(errs, fmt.Errorf("%v in enable-admission-plugins and disable-admission-plugins "+
+ "overlapped", enablePlugins.Intersection(disablePlugins).List()))
+ }
+
+ // Verify RecommendedPluginOrder.
+ recommendPlugins := sets.NewString(a.RecommendedPluginOrder...)
+ intersections := registeredPlugins.Intersection(recommendPlugins)
+ if !intersections.Equal(recommendPlugins) {
+ // Developer error, this should never run in.
+ errs = append(errs, fmt.Errorf("plugins %v in RecommendedPluginOrder are not registered",
+ recommendPlugins.Difference(intersections).List()))
+ }
+ if !intersections.Equal(registeredPlugins) {
+ // Developer error, this should never run in.
+ errs = append(errs, fmt.Errorf("plugins %v registered are not in RecommendedPluginOrder",
+ registeredPlugins.Difference(intersections).List()))
+ }
+
+ return errs
+}
+
+// enabledPluginNames makes use of RecommendedPluginOrder, DefaultOffPlugins,
+// EnablePlugins, DisablePlugins fields
+// to prepare a list of ordered plugin names that are enabled.
+func (a *AdmissionOptions) enabledPluginNames() []string {
+ allOffPlugins := append(a.DefaultOffPlugins.List(), a.DisablePlugins...)
+ disabledPlugins := sets.NewString(allOffPlugins...)
+ enabledPlugins := sets.NewString(a.EnablePlugins...)
+ disabledPlugins = disabledPlugins.Difference(enabledPlugins)
+
+ orderedPlugins := []string{}
+ for _, plugin := range a.RecommendedPluginOrder {
+ if !disabledPlugins.Has(plugin) {
+ orderedPlugins = append(orderedPlugins, plugin)
+ }
+ }
+
+ return orderedPlugins
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/api_enablement.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/api_enablement.go
new file mode 100644
index 0000000..8c64bee
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/api_enablement.go
@@ -0,0 +1,111 @@
+/*
+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 options
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/pflag"
+
+ "k8s.io/apiserver/pkg/server"
+ "k8s.io/apiserver/pkg/server/resourceconfig"
+ serverstore "k8s.io/apiserver/pkg/server/storage"
+ utilflag "k8s.io/apiserver/pkg/util/flag"
+)
+
+// APIEnablementOptions contains the options for which resources to turn on and off.
+// Given small aggregated API servers, this option isn't required for "normal" API servers
+type APIEnablementOptions struct {
+ RuntimeConfig utilflag.ConfigurationMap
+}
+
+func NewAPIEnablementOptions() *APIEnablementOptions {
+ return &APIEnablementOptions{
+ RuntimeConfig: make(utilflag.ConfigurationMap),
+ }
+}
+
+// AddFlags adds flags for a specific APIServer to the specified FlagSet
+func (s *APIEnablementOptions) AddFlags(fs *pflag.FlagSet) {
+ fs.Var(&s.RuntimeConfig, "runtime-config", ""+
+ "A set of key=value pairs that describe runtime configuration that may be passed "+
+ "to apiserver. <group>/<version> (or <version> for the core group) key can be used to "+
+ "turn on/off specific api versions. api/all is special key to control all api versions, "+
+ "be careful setting it false, unless you know what you do. api/legacy is deprecated, "+
+ "we will remove it in the future, so stop using it.")
+}
+
+// Validate validates RuntimeConfig with a list of registries.
+// Usually this list only has one element, the apiserver registry of the process.
+// But in the advanced (and usually not recommended) case of delegated apiservers there can be more.
+// Validate will filter out the known groups of each registry.
+// If anything is left over after that, an error is returned.
+func (s *APIEnablementOptions) Validate(registries ...GroupRegisty) []error {
+ if s == nil {
+ return nil
+ }
+
+ errors := []error{}
+ if s.RuntimeConfig["api/all"] == "false" && len(s.RuntimeConfig) == 1 {
+ // Do not allow only set api/all=false, in such case apiserver startup has no meaning.
+ return append(errors, fmt.Errorf("invliad key with only api/all=false"))
+ }
+
+ groups, err := resourceconfig.ParseGroups(s.RuntimeConfig)
+ if err != nil {
+ return append(errors, err)
+ }
+
+ for _, registry := range registries {
+ // filter out known groups
+ groups = unknownGroups(groups, registry)
+ }
+ if len(groups) != 0 {
+ errors = append(errors, fmt.Errorf("unknown api groups %s", strings.Join(groups, ",")))
+ }
+
+ return errors
+}
+
+// ApplyTo override MergedResourceConfig with defaults and registry
+func (s *APIEnablementOptions) ApplyTo(c *server.Config, defaultResourceConfig *serverstore.ResourceConfig, registry resourceconfig.GroupVersionRegistry) error {
+ if s == nil {
+ return nil
+ }
+
+ mergedResourceConfig, err := resourceconfig.MergeAPIResourceConfigs(defaultResourceConfig, s.RuntimeConfig, registry)
+ c.MergedResourceConfig = mergedResourceConfig
+
+ return err
+}
+
+func unknownGroups(groups []string, registry GroupRegisty) []string {
+ unknownGroups := []string{}
+ for _, group := range groups {
+ if !registry.IsGroupRegistered(group) {
+ unknownGroups = append(unknownGroups, group)
+ }
+ }
+ return unknownGroups
+}
+
+// GroupRegisty provides a method to check whether given group is registered.
+type GroupRegisty interface {
+ // IsRegistered returns true if given group is registered.
+ IsGroupRegistered(group string) bool
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/audit.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/audit.go
new file mode 100644
index 0000000..ab77812
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/audit.go
@@ -0,0 +1,523 @@
+/*
+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 options
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/golang/glog"
+ "github.com/spf13/pflag"
+ "gopkg.in/natefinch/lumberjack.v2"
+
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
+ auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
+ "k8s.io/apiserver/pkg/audit"
+ "k8s.io/apiserver/pkg/audit/policy"
+ "k8s.io/apiserver/pkg/features"
+ "k8s.io/apiserver/pkg/server"
+ utilfeature "k8s.io/apiserver/pkg/util/feature"
+ pluginbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered"
+ pluginlog "k8s.io/apiserver/plugin/pkg/audit/log"
+ plugintruncate "k8s.io/apiserver/plugin/pkg/audit/truncate"
+ pluginwebhook "k8s.io/apiserver/plugin/pkg/audit/webhook"
+)
+
+func appendBackend(existing, newBackend audit.Backend) audit.Backend {
+ if existing == nil {
+ return newBackend
+ }
+ return audit.Union(existing, newBackend)
+}
+
+func advancedAuditingEnabled() bool {
+ return utilfeature.DefaultFeatureGate.Enabled(features.AdvancedAuditing)
+}
+
+type AuditOptions struct {
+ // Policy configuration file for filtering audit events that are captured.
+ // If unspecified, a default is provided.
+ PolicyFile string
+
+ // Plugin options
+
+ LogOptions AuditLogOptions
+ WebhookOptions AuditWebhookOptions
+}
+
+const (
+ // ModeBatch indicates that the audit backend should buffer audit events
+ // internally, sending batch updates either once a certain number of
+ // events have been received or a certain amount of time has passed.
+ ModeBatch = "batch"
+ // ModeBlocking causes the audit backend to block on every attempt to process
+ // a set of events. This causes requests to the API server to wait for the
+ // flush before sending a response.
+ ModeBlocking = "blocking"
+)
+
+// AllowedModes is the modes known for audit backends.
+var AllowedModes = []string{
+ ModeBatch,
+ ModeBlocking,
+}
+
+type AuditBatchOptions struct {
+ // Should the backend asynchronous batch events to the webhook backend or
+ // should the backend block responses?
+ //
+ // Defaults to asynchronous batch events.
+ Mode string
+ // Configuration for batching backend. Only used in batch mode.
+ BatchConfig pluginbuffered.BatchConfig
+}
+
+type AuditTruncateOptions struct {
+ // Whether truncating is enabled or not.
+ Enabled bool
+
+ // Truncating configuration.
+ TruncateConfig plugintruncate.Config
+}
+
+// AuditLogOptions determines the output of the structured audit log by default.
+// If the AdvancedAuditing feature is set to false, AuditLogOptions holds the legacy
+// audit log writer.
+type AuditLogOptions struct {
+ Path string
+ MaxAge int
+ MaxBackups int
+ MaxSize int
+ Format string
+
+ BatchOptions AuditBatchOptions
+ TruncateOptions AuditTruncateOptions
+
+ // API group version used for serializing audit events.
+ GroupVersionString string
+}
+
+// AuditWebhookOptions control the webhook configuration for audit events.
+type AuditWebhookOptions struct {
+ ConfigFile string
+ InitialBackoff time.Duration
+
+ BatchOptions AuditBatchOptions
+ TruncateOptions AuditTruncateOptions
+
+ // API group version used for serializing audit events.
+ GroupVersionString string
+}
+
+func NewAuditOptions() *AuditOptions {
+ defaultLogBatchConfig := pluginbuffered.NewDefaultBatchConfig()
+ defaultLogBatchConfig.ThrottleEnable = false
+
+ return &AuditOptions{
+ WebhookOptions: AuditWebhookOptions{
+ InitialBackoff: pluginwebhook.DefaultInitialBackoff,
+ BatchOptions: AuditBatchOptions{
+ Mode: ModeBatch,
+ BatchConfig: pluginbuffered.NewDefaultBatchConfig(),
+ },
+ TruncateOptions: NewAuditTruncateOptions(),
+ GroupVersionString: "audit.k8s.io/v1beta1",
+ },
+ LogOptions: AuditLogOptions{
+ Format: pluginlog.FormatJson,
+ BatchOptions: AuditBatchOptions{
+ Mode: ModeBlocking,
+ BatchConfig: defaultLogBatchConfig,
+ },
+ TruncateOptions: NewAuditTruncateOptions(),
+ GroupVersionString: "audit.k8s.io/v1beta1",
+ },
+ }
+}
+
+func NewAuditTruncateOptions() AuditTruncateOptions {
+ return AuditTruncateOptions{
+ Enabled: false,
+ TruncateConfig: plugintruncate.Config{
+ MaxBatchSize: 10 * 1024 * 1024, // 10MB
+ MaxEventSize: 100 * 1024, // 100KB
+ },
+ }
+}
+
+// Validate checks invalid config combination
+func (o *AuditOptions) Validate() []error {
+ if o == nil {
+ return nil
+ }
+
+ allErrors := []error{}
+
+ if !advancedAuditingEnabled() {
+ if len(o.PolicyFile) > 0 {
+ allErrors = append(allErrors, fmt.Errorf("feature '%s' must be enabled to set option --audit-policy-file", features.AdvancedAuditing))
+ }
+ if len(o.WebhookOptions.ConfigFile) > 0 {
+ allErrors = append(allErrors, fmt.Errorf("feature '%s' must be enabled to set option --audit-webhook-config-file", features.AdvancedAuditing))
+ }
+ }
+
+ allErrors = append(allErrors, o.LogOptions.Validate()...)
+ allErrors = append(allErrors, o.WebhookOptions.Validate()...)
+
+ return allErrors
+}
+
+func validateBackendMode(pluginName string, mode string) error {
+ for _, m := range AllowedModes {
+ if m == mode {
+ return nil
+ }
+ }
+ return fmt.Errorf("invalid audit %s mode %s, allowed modes are %q", pluginName, mode, strings.Join(AllowedModes, ","))
+}
+
+func validateBackendBatchOptions(pluginName string, options AuditBatchOptions) error {
+ if err := validateBackendMode(pluginName, options.Mode); err != nil {
+ return err
+ }
+ if options.Mode != ModeBatch {
+ // Don't validate the unused options.
+ return nil
+ }
+ config := options.BatchConfig
+ if config.BufferSize <= 0 {
+ return fmt.Errorf("invalid audit batch %s buffer size %v, must be a positive number", pluginName, config.BufferSize)
+ }
+ if config.MaxBatchSize <= 0 {
+ return fmt.Errorf("invalid audit batch %s max batch size %v, must be a positive number", pluginName, config.MaxBatchSize)
+ }
+ if config.ThrottleQPS <= 0 {
+ return fmt.Errorf("invalid audit batch %s throttle QPS %v, must be a positive number", pluginName, config.ThrottleQPS)
+ }
+ if config.ThrottleBurst <= 0 {
+ return fmt.Errorf("invalid audit batch %s throttle burst %v, must be a positive number", pluginName, config.ThrottleBurst)
+ }
+ return nil
+}
+
+var knownGroupVersions = []schema.GroupVersion{
+ auditv1alpha1.SchemeGroupVersion,
+ auditv1beta1.SchemeGroupVersion,
+}
+
+func validateGroupVersionString(groupVersion string) error {
+ gv, err := schema.ParseGroupVersion(groupVersion)
+ if err != nil {
+ return err
+ }
+ if !knownGroupVersion(gv) {
+ return fmt.Errorf("invalid group version, allowed versions are %q", knownGroupVersions)
+ }
+ return nil
+}
+
+func knownGroupVersion(gv schema.GroupVersion) bool {
+ for _, knownGv := range knownGroupVersions {
+ if gv == knownGv {
+ return true
+ }
+ }
+ return false
+}
+
+func (o *AuditOptions) AddFlags(fs *pflag.FlagSet) {
+ if o == nil {
+ return
+ }
+
+ fs.StringVar(&o.PolicyFile, "audit-policy-file", o.PolicyFile,
+ "Path to the file that defines the audit policy configuration. Requires the 'AdvancedAuditing' feature gate."+
+ " With AdvancedAuditing, a profile is required to enable auditing.")
+
+ o.LogOptions.AddFlags(fs)
+ o.LogOptions.BatchOptions.AddFlags(pluginlog.PluginName, fs)
+ o.LogOptions.TruncateOptions.AddFlags(pluginlog.PluginName, fs)
+ o.WebhookOptions.AddFlags(fs)
+ o.WebhookOptions.BatchOptions.AddFlags(pluginwebhook.PluginName, fs)
+ o.WebhookOptions.TruncateOptions.AddFlags(pluginwebhook.PluginName, fs)
+}
+
+func (o *AuditOptions) ApplyTo(c *server.Config) error {
+ if o == nil {
+ return nil
+ }
+
+ // Apply legacy audit options if advanced audit is not enabled.
+ if !advancedAuditingEnabled() {
+ return o.LogOptions.legacyApplyTo(c)
+ }
+
+ // Apply advanced options if advanced audit is enabled.
+ // 1. Apply generic options.
+ if err := o.applyTo(c); err != nil {
+ return err
+ }
+
+ // 2. Apply plugin options.
+ if err := o.LogOptions.advancedApplyTo(c); err != nil {
+ return err
+ }
+ if err := o.WebhookOptions.applyTo(c); err != nil {
+ return err
+ }
+
+ if c.AuditBackend != nil && c.AuditPolicyChecker == nil {
+ glog.V(2).Info("No audit policy file provided for AdvancedAuditing, no events will be recorded.")
+ }
+ return nil
+}
+
+func (o *AuditOptions) applyTo(c *server.Config) error {
+ if o.PolicyFile == "" {
+ return nil
+ }
+
+ p, err := policy.LoadPolicyFromFile(o.PolicyFile)
+ if err != nil {
+ return fmt.Errorf("loading audit policy file: %v", err)
+ }
+ c.AuditPolicyChecker = policy.NewChecker(p)
+ return nil
+}
+
+func (o *AuditBatchOptions) AddFlags(pluginName string, fs *pflag.FlagSet) {
+ fs.StringVar(&o.Mode, fmt.Sprintf("audit-%s-mode", pluginName), o.Mode,
+ "Strategy for sending audit events. Blocking indicates sending events should block"+
+ " server responses. Batch causes the backend to buffer and write events"+
+ " asynchronously. Known modes are "+strings.Join(AllowedModes, ",")+".")
+ fs.IntVar(&o.BatchConfig.BufferSize, fmt.Sprintf("audit-%s-batch-buffer-size", pluginName),
+ o.BatchConfig.BufferSize, "The size of the buffer to store events before "+
+ "batching and writing. Only used in batch mode.")
+ fs.IntVar(&o.BatchConfig.MaxBatchSize, fmt.Sprintf("audit-%s-batch-max-size", pluginName),
+ o.BatchConfig.MaxBatchSize, "The maximum size of a batch. Only used in batch mode.")
+ fs.DurationVar(&o.BatchConfig.MaxBatchWait, fmt.Sprintf("audit-%s-batch-max-wait", pluginName),
+ o.BatchConfig.MaxBatchWait, "The amount of time to wait before force writing the "+
+ "batch that hadn't reached the max size. Only used in batch mode.")
+ fs.BoolVar(&o.BatchConfig.ThrottleEnable, fmt.Sprintf("audit-%s-batch-throttle-enable", pluginName),
+ o.BatchConfig.ThrottleEnable, "Whether batching throttling is enabled. Only used in batch mode.")
+ fs.Float32Var(&o.BatchConfig.ThrottleQPS, fmt.Sprintf("audit-%s-batch-throttle-qps", pluginName),
+ o.BatchConfig.ThrottleQPS, "Maximum average number of batches per second. "+
+ "Only used in batch mode.")
+ fs.IntVar(&o.BatchConfig.ThrottleBurst, fmt.Sprintf("audit-%s-batch-throttle-burst", pluginName),
+ o.BatchConfig.ThrottleBurst, "Maximum number of requests sent at the same "+
+ "moment if ThrottleQPS was not utilized before. Only used in batch mode.")
+}
+
+func (o *AuditBatchOptions) wrapBackend(delegate audit.Backend) audit.Backend {
+ if o.Mode == ModeBlocking {
+ return delegate
+ }
+ return pluginbuffered.NewBackend(delegate, o.BatchConfig)
+}
+
+func (o *AuditTruncateOptions) Validate(pluginName string) error {
+ config := o.TruncateConfig
+ if config.MaxEventSize <= 0 {
+ return fmt.Errorf("invalid audit truncate %s max event size %v, must be a positive number", pluginName, config.MaxEventSize)
+ }
+ if config.MaxBatchSize < config.MaxEventSize {
+ return fmt.Errorf("invalid audit truncate %s max batch size %v, must be greater than "+
+ "max event size (%v)", pluginName, config.MaxBatchSize, config.MaxEventSize)
+ }
+ return nil
+}
+
+func (o *AuditTruncateOptions) AddFlags(pluginName string, fs *pflag.FlagSet) {
+ fs.BoolVar(&o.Enabled, fmt.Sprintf("audit-%s-truncate-enabled", pluginName),
+ o.Enabled, "Whether event and batch truncating is enabled.")
+ fs.Int64Var(&o.TruncateConfig.MaxBatchSize, fmt.Sprintf("audit-%s-truncate-max-batch-size", pluginName),
+ o.TruncateConfig.MaxBatchSize, "Maximum size of the batch sent to the underlying backend. "+
+ "Actual serialized size can be several hundreds of bytes greater. If a batch exceeds this limit, "+
+ "it is split into several batches of smaller size.")
+ fs.Int64Var(&o.TruncateConfig.MaxEventSize, fmt.Sprintf("audit-%s-truncate-max-event-size", pluginName),
+ o.TruncateConfig.MaxEventSize, "Maximum size of the audit event sent to the underlying backend. "+
+ "If the size of an event is greater than this number, first request and response are removed, and"+
+ "if this doesn't reduce the size enough, event is discarded.")
+}
+
+func (o *AuditTruncateOptions) wrapBackend(delegate audit.Backend, gv schema.GroupVersion) audit.Backend {
+ if !o.Enabled {
+ return delegate
+ }
+ return plugintruncate.NewBackend(delegate, o.TruncateConfig, gv)
+}
+
+func (o *AuditLogOptions) AddFlags(fs *pflag.FlagSet) {
+ fs.StringVar(&o.Path, "audit-log-path", o.Path,
+ "If set, all requests coming to the apiserver will be logged to this file. '-' means standard out.")
+ fs.IntVar(&o.MaxAge, "audit-log-maxage", o.MaxBackups,
+ "The maximum number of days to retain old audit log files based on the timestamp encoded in their filename.")
+ fs.IntVar(&o.MaxBackups, "audit-log-maxbackup", o.MaxBackups,
+ "The maximum number of old audit log files to retain.")
+ fs.IntVar(&o.MaxSize, "audit-log-maxsize", o.MaxSize,
+ "The maximum size in megabytes of the audit log file before it gets rotated.")
+ fs.StringVar(&o.Format, "audit-log-format", o.Format,
+ "Format of saved audits. \"legacy\" indicates 1-line text format for each event."+
+ " \"json\" indicates structured json format. Requires the 'AdvancedAuditing' feature"+
+ " gate. Known formats are "+strings.Join(pluginlog.AllowedFormats, ",")+".")
+ fs.StringVar(&o.GroupVersionString, "audit-log-version", o.GroupVersionString,
+ "API group and version used for serializing audit events written to log.")
+}
+
+func (o *AuditLogOptions) Validate() []error {
+ // Check whether the log backend is enabled based on the options.
+ if !o.enabled() {
+ return nil
+ }
+
+ var allErrors []error
+ if advancedAuditingEnabled() {
+ if err := validateBackendBatchOptions(pluginlog.PluginName, o.BatchOptions); err != nil {
+ allErrors = append(allErrors, err)
+ }
+ if err := o.TruncateOptions.Validate(pluginlog.PluginName); err != nil {
+ allErrors = append(allErrors, err)
+ }
+
+ if err := validateGroupVersionString(o.GroupVersionString); err != nil {
+ allErrors = append(allErrors, err)
+ }
+
+ // Check log format
+ validFormat := false
+ for _, f := range pluginlog.AllowedFormats {
+ if f == o.Format {
+ validFormat = true
+ break
+ }
+ }
+ if !validFormat {
+ allErrors = append(allErrors, fmt.Errorf("invalid audit log format %s, allowed formats are %q", o.Format, strings.Join(pluginlog.AllowedFormats, ",")))
+ }
+ }
+
+ // Check validities of MaxAge, MaxBackups and MaxSize of log options, if file log backend is enabled.
+ if o.MaxAge < 0 {
+ allErrors = append(allErrors, fmt.Errorf("--audit-log-maxage %v can't be a negative number", o.MaxAge))
+ }
+ if o.MaxBackups < 0 {
+ allErrors = append(allErrors, fmt.Errorf("--audit-log-maxbackup %v can't be a negative number", o.MaxBackups))
+ }
+ if o.MaxSize < 0 {
+ allErrors = append(allErrors, fmt.Errorf("--audit-log-maxsize %v can't be a negative number", o.MaxSize))
+ }
+
+ return allErrors
+}
+
+// Check whether the log backend is enabled based on the options.
+func (o *AuditLogOptions) enabled() bool {
+ return o != nil && o.Path != ""
+}
+
+func (o *AuditLogOptions) getWriter() io.Writer {
+ if !o.enabled() {
+ return nil
+ }
+
+ var w io.Writer = os.Stdout
+ if o.Path != "-" {
+ w = &lumberjack.Logger{
+ Filename: o.Path,
+ MaxAge: o.MaxAge,
+ MaxBackups: o.MaxBackups,
+ MaxSize: o.MaxSize,
+ }
+ }
+ return w
+}
+
+func (o *AuditLogOptions) advancedApplyTo(c *server.Config) error {
+ if w := o.getWriter(); w != nil {
+ groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString)
+ log := pluginlog.NewBackend(w, o.Format, groupVersion)
+ log = o.BatchOptions.wrapBackend(log)
+ log = o.TruncateOptions.wrapBackend(log, groupVersion)
+ c.AuditBackend = appendBackend(c.AuditBackend, log)
+ }
+ return nil
+}
+
+func (o *AuditLogOptions) legacyApplyTo(c *server.Config) error {
+ c.LegacyAuditWriter = o.getWriter()
+ return nil
+}
+
+func (o *AuditWebhookOptions) AddFlags(fs *pflag.FlagSet) {
+ fs.StringVar(&o.ConfigFile, "audit-webhook-config-file", o.ConfigFile,
+ "Path to a kubeconfig formatted file that defines the audit webhook configuration."+
+ " Requires the 'AdvancedAuditing' feature gate.")
+ fs.DurationVar(&o.InitialBackoff, "audit-webhook-initial-backoff",
+ o.InitialBackoff, "The amount of time to wait before retrying the first failed request.")
+ fs.DurationVar(&o.InitialBackoff, "audit-webhook-batch-initial-backoff",
+ o.InitialBackoff, "The amount of time to wait before retrying the first failed request.")
+ fs.MarkDeprecated("audit-webhook-batch-initial-backoff",
+ "Deprecated, use --audit-webhook-initial-backoff instead.")
+ fs.StringVar(&o.GroupVersionString, "audit-webhook-version", o.GroupVersionString,
+ "API group and version used for serializing audit events written to webhook.")
+}
+
+func (o *AuditWebhookOptions) Validate() []error {
+ if !o.enabled() {
+ return nil
+ }
+
+ var allErrors []error
+ if advancedAuditingEnabled() {
+ if err := validateBackendBatchOptions(pluginwebhook.PluginName, o.BatchOptions); err != nil {
+ allErrors = append(allErrors, err)
+ }
+ if err := o.TruncateOptions.Validate(pluginwebhook.PluginName); err != nil {
+ allErrors = append(allErrors, err)
+ }
+
+ if err := validateGroupVersionString(o.GroupVersionString); err != nil {
+ allErrors = append(allErrors, err)
+ }
+ }
+ return allErrors
+}
+
+func (o *AuditWebhookOptions) enabled() bool {
+ return o != nil && o.ConfigFile != ""
+}
+
+func (o *AuditWebhookOptions) applyTo(c *server.Config) error {
+ if !o.enabled() {
+ return nil
+ }
+
+ groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString)
+ webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff)
+ if err != nil {
+ return fmt.Errorf("initializing audit webhook: %v", err)
+ }
+ webhook = o.BatchOptions.wrapBackend(webhook)
+ webhook = o.TruncateOptions.wrapBackend(webhook, groupVersion)
+ c.AuditBackend = appendBackend(c.AuditBackend, webhook)
+ return nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/authentication.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/authentication.go
new file mode 100644
index 0000000..2ec5024
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/authentication.go
@@ -0,0 +1,406 @@
+/*
+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 options
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "time"
+
+ "github.com/golang/glog"
+ "github.com/spf13/pflag"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apiserver/pkg/authentication/authenticatorfactory"
+ "k8s.io/apiserver/pkg/server"
+ authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1"
+ coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+ openapicommon "k8s.io/kube-openapi/pkg/common"
+)
+
+type RequestHeaderAuthenticationOptions struct {
+ UsernameHeaders []string
+ GroupHeaders []string
+ ExtraHeaderPrefixes []string
+ ClientCAFile string
+ AllowedNames []string
+}
+
+func (s *RequestHeaderAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
+ if s == nil {
+ return
+ }
+
+ fs.StringSliceVar(&s.UsernameHeaders, "requestheader-username-headers", s.UsernameHeaders, ""+
+ "List of request headers to inspect for usernames. X-Remote-User is common.")
+
+ fs.StringSliceVar(&s.GroupHeaders, "requestheader-group-headers", s.GroupHeaders, ""+
+ "List of request headers to inspect for groups. X-Remote-Group is suggested.")
+
+ fs.StringSliceVar(&s.ExtraHeaderPrefixes, "requestheader-extra-headers-prefix", s.ExtraHeaderPrefixes, ""+
+ "List of request header prefixes to inspect. X-Remote-Extra- is suggested.")
+
+ fs.StringVar(&s.ClientCAFile, "requestheader-client-ca-file", s.ClientCAFile, ""+
+ "Root certificate bundle to use to verify client certificates on incoming requests "+
+ "before trusting usernames in headers specified by --requestheader-username-headers. "+
+ "WARNING: generally do not depend on authorization being already done for incoming requests.")
+
+ fs.StringSliceVar(&s.AllowedNames, "requestheader-allowed-names", s.AllowedNames, ""+
+ "List of client certificate common names to allow to provide usernames in headers "+
+ "specified by --requestheader-username-headers. If empty, any client certificate validated "+
+ "by the authorities in --requestheader-client-ca-file is allowed.")
+}
+
+// ToAuthenticationRequestHeaderConfig returns a RequestHeaderConfig config object for these options
+// if necessary, nil otherwise.
+func (s *RequestHeaderAuthenticationOptions) ToAuthenticationRequestHeaderConfig() *authenticatorfactory.RequestHeaderConfig {
+ if len(s.ClientCAFile) == 0 {
+ return nil
+ }
+
+ return &authenticatorfactory.RequestHeaderConfig{
+ UsernameHeaders: s.UsernameHeaders,
+ GroupHeaders: s.GroupHeaders,
+ ExtraHeaderPrefixes: s.ExtraHeaderPrefixes,
+ ClientCA: s.ClientCAFile,
+ AllowedClientNames: s.AllowedNames,
+ }
+}
+
+type ClientCertAuthenticationOptions struct {
+ // ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates
+ ClientCA string
+}
+
+func (s *ClientCertAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
+ fs.StringVar(&s.ClientCA, "client-ca-file", s.ClientCA, ""+
+ "If set, any request presenting a client certificate signed by one of "+
+ "the authorities in the client-ca-file is authenticated with an identity "+
+ "corresponding to the CommonName of the client certificate.")
+}
+
+// DelegatingAuthenticationOptions provides an easy way for composing API servers to delegate their authentication to
+// the root kube API server. The API federator will act as
+// a front proxy and direction connections will be able to delegate to the core kube API server
+type DelegatingAuthenticationOptions struct {
+ // RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the
+ // TokenAccessReview.authentication.k8s.io endpoint for checking tokens.
+ RemoteKubeConfigFile string
+
+ // CacheTTL is the length of time that a token authentication answer will be cached.
+ CacheTTL time.Duration
+
+ ClientCert ClientCertAuthenticationOptions
+ RequestHeader RequestHeaderAuthenticationOptions
+
+ SkipInClusterLookup bool
+}
+
+func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions {
+ return &DelegatingAuthenticationOptions{
+ // very low for responsiveness, but high enough to handle storms
+ CacheTTL: 10 * time.Second,
+ ClientCert: ClientCertAuthenticationOptions{},
+ RequestHeader: RequestHeaderAuthenticationOptions{
+ UsernameHeaders: []string{"x-remote-user"},
+ GroupHeaders: []string{"x-remote-group"},
+ ExtraHeaderPrefixes: []string{"x-remote-extra-"},
+ },
+ }
+}
+
+func (s *DelegatingAuthenticationOptions) Validate() []error {
+ allErrors := []error{}
+ return allErrors
+}
+
+func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
+ if s == nil {
+ return
+ }
+
+ fs.StringVar(&s.RemoteKubeConfigFile, "authentication-kubeconfig", s.RemoteKubeConfigFile, ""+
+ "kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
+ "tokenaccessreviews.authentication.k8s.io.")
+
+ fs.DurationVar(&s.CacheTTL, "authentication-token-webhook-cache-ttl", s.CacheTTL,
+ "The duration to cache responses from the webhook token authenticator.")
+
+ s.ClientCert.AddFlags(fs)
+ s.RequestHeader.AddFlags(fs)
+
+ fs.BoolVar(&s.SkipInClusterLookup, "authentication-skip-lookup", s.SkipInClusterLookup, ""+
+ "If false, the authentication-kubeconfig will be used to lookup missing authentication "+
+ "configuration from the cluster.")
+
+}
+
+func (s *DelegatingAuthenticationOptions) ApplyTo(c *server.AuthenticationInfo, servingInfo *server.SecureServingInfo, openAPIConfig *openapicommon.Config) error {
+ if s == nil {
+ c.Authenticator = nil
+ return nil
+ }
+
+ clientCA, err := s.getClientCA()
+ if err != nil {
+ if _, ignorable := err.(ignorableError); !ignorable {
+ return err
+ } else {
+ glog.Warning(err)
+ }
+ }
+ if err = c.ApplyClientCert(clientCA.ClientCA, servingInfo); err != nil {
+ return fmt.Errorf("unable to load client CA file: %v", err)
+ }
+
+ requestHeader, err := s.getRequestHeader()
+ if err != nil {
+ return err
+ }
+ if err = c.ApplyClientCert(requestHeader.ClientCAFile, servingInfo); err != nil {
+ return fmt.Errorf("unable to load client CA file: %v", err)
+ }
+
+ cfg, err := s.ToAuthenticationConfig()
+ if err != nil {
+ return err
+ }
+ authenticator, securityDefinitions, err := cfg.New()
+ if err != nil {
+ return err
+ }
+
+ c.Authenticator = authenticator
+ if openAPIConfig != nil {
+ openAPIConfig.SecurityDefinitions = securityDefinitions
+ }
+ c.SupportsBasicAuth = false
+
+ return nil
+}
+
+func (s *DelegatingAuthenticationOptions) ToAuthenticationConfig() (authenticatorfactory.DelegatingAuthenticatorConfig, error) {
+ tokenClient, err := s.newTokenAccessReview()
+ if err != nil {
+ return authenticatorfactory.DelegatingAuthenticatorConfig{}, err
+ }
+
+ clientCA, err := s.getClientCA()
+ if err != nil {
+ if _, ignorable := err.(ignorableError); !ignorable {
+ return authenticatorfactory.DelegatingAuthenticatorConfig{}, err
+ } else {
+ glog.Warning(err)
+ }
+ }
+ requestHeader, err := s.getRequestHeader()
+ if err != nil {
+ return authenticatorfactory.DelegatingAuthenticatorConfig{}, err
+ }
+
+ ret := authenticatorfactory.DelegatingAuthenticatorConfig{
+ Anonymous: true,
+ TokenAccessReviewClient: tokenClient,
+ CacheTTL: s.CacheTTL,
+ ClientCAFile: clientCA.ClientCA,
+ RequestHeaderConfig: requestHeader.ToAuthenticationRequestHeaderConfig(),
+ }
+ return ret, nil
+}
+
+const (
+ authenticationConfigMapNamespace = metav1.NamespaceSystem
+ // authenticationConfigMapName is the name of ConfigMap in the kube-system namespace holding the root certificate
+ // bundle to use to verify client certificates on incoming requests before trusting usernames in headers specified
+ // by --requestheader-username-headers. This is created in the cluster by the kube-apiserver.
+ // "WARNING: generally do not depend on authorization being already done for incoming requests.")
+ authenticationConfigMapName = "extension-apiserver-authentication"
+ authenticationRoleName = "extension-apiserver-authentication-reader"
+)
+
+func (s *DelegatingAuthenticationOptions) getClientCA() (*ClientCertAuthenticationOptions, error) {
+ if len(s.ClientCert.ClientCA) > 0 || s.SkipInClusterLookup {
+ return &s.ClientCert, nil
+ }
+
+ incluster, err := s.lookupInClusterClientCA()
+ if err != nil {
+ glog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+
+ "'kubectl create rolebinding -n %s ROLE_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'",
+ authenticationConfigMapName, authenticationConfigMapNamespace, authenticationConfigMapNamespace, authenticationRoleName)
+ return nil, err
+ }
+ if incluster == nil {
+ return &s.ClientCert, ignorableError{fmt.Errorf("cluster doesn't provide client-ca-file in configmap/%s in %s, so client certificate authentication to extension api-server won't work.", authenticationConfigMapName, authenticationConfigMapNamespace)}
+ }
+ return incluster, nil
+}
+
+func (s *DelegatingAuthenticationOptions) getRequestHeader() (*RequestHeaderAuthenticationOptions, error) {
+ if len(s.RequestHeader.ClientCAFile) > 0 || s.SkipInClusterLookup {
+ return &s.RequestHeader, nil
+ }
+
+ incluster, err := s.lookupInClusterRequestHeader()
+ if err != nil {
+ glog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+
+ "'kubectl create rolebinding -n %s ROLE_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'",
+ authenticationConfigMapName, authenticationConfigMapNamespace, authenticationConfigMapNamespace, authenticationRoleName)
+ return nil, err
+ }
+ if incluster == nil {
+ return nil, fmt.Errorf("cluster doesn't provide requestheader-client-ca-file")
+ }
+ return incluster, nil
+}
+
+func (s *DelegatingAuthenticationOptions) lookupInClusterClientCA() (*ClientCertAuthenticationOptions, error) {
+ clientConfig, err := s.getClientConfig()
+ if err != nil {
+ return nil, err
+ }
+ client, err := coreclient.NewForConfig(clientConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ authConfigMap, err := client.ConfigMaps(authenticationConfigMapNamespace).Get(authenticationConfigMapName, metav1.GetOptions{})
+ if err != nil {
+ return nil, err
+ }
+
+ clientCA, ok := authConfigMap.Data["client-ca-file"]
+ if !ok {
+ return nil, nil
+ }
+
+ f, err := ioutil.TempFile("", "client-ca-file")
+ if err != nil {
+ return nil, err
+ }
+ if err := ioutil.WriteFile(f.Name(), []byte(clientCA), 0600); err != nil {
+ return nil, err
+ }
+ return &ClientCertAuthenticationOptions{ClientCA: f.Name()}, nil
+}
+
+func (s *DelegatingAuthenticationOptions) lookupInClusterRequestHeader() (*RequestHeaderAuthenticationOptions, error) {
+ clientConfig, err := s.getClientConfig()
+ if err != nil {
+ return nil, err
+ }
+ client, err := coreclient.NewForConfig(clientConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ authConfigMap, err := client.ConfigMaps(authenticationConfigMapNamespace).Get(authenticationConfigMapName, metav1.GetOptions{})
+ if err != nil {
+ return nil, err
+ }
+
+ requestHeaderCA, ok := authConfigMap.Data["requestheader-client-ca-file"]
+ if !ok {
+ return nil, nil
+ }
+
+ f, err := ioutil.TempFile("", "requestheader-client-ca-file")
+ if err != nil {
+ return nil, err
+ }
+ if err := ioutil.WriteFile(f.Name(), []byte(requestHeaderCA), 0600); err != nil {
+ return nil, err
+ }
+ usernameHeaders, err := deserializeStrings(authConfigMap.Data["requestheader-username-headers"])
+ if err != nil {
+ return nil, err
+ }
+ groupHeaders, err := deserializeStrings(authConfigMap.Data["requestheader-group-headers"])
+ if err != nil {
+ return nil, err
+ }
+ extraHeaderPrefixes, err := deserializeStrings(authConfigMap.Data["requestheader-extra-headers-prefix"])
+ if err != nil {
+ return nil, err
+ }
+ allowedNames, err := deserializeStrings(authConfigMap.Data["requestheader-allowed-names"])
+ if err != nil {
+ return nil, err
+ }
+
+ return &RequestHeaderAuthenticationOptions{
+ UsernameHeaders: usernameHeaders,
+ GroupHeaders: groupHeaders,
+ ExtraHeaderPrefixes: extraHeaderPrefixes,
+ ClientCAFile: f.Name(),
+ AllowedNames: allowedNames,
+ }, nil
+}
+
+func deserializeStrings(in string) ([]string, error) {
+ if len(in) == 0 {
+ return nil, nil
+ }
+ var ret []string
+ if err := json.Unmarshal([]byte(in), &ret); err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+func (s *DelegatingAuthenticationOptions) getClientConfig() (*rest.Config, error) {
+ var clientConfig *rest.Config
+ var err error
+ if len(s.RemoteKubeConfigFile) > 0 {
+ loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile}
+ loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
+
+ clientConfig, err = loader.ClientConfig()
+
+ } else {
+ // without the remote kubeconfig file, try to use the in-cluster config. Most addon API servers will
+ // use this path
+ clientConfig, err = rest.InClusterConfig()
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ // set high qps/burst limits since this will effectively limit API server responsiveness
+ clientConfig.QPS = 200
+ clientConfig.Burst = 400
+
+ return clientConfig, nil
+}
+
+func (s *DelegatingAuthenticationOptions) newTokenAccessReview() (authenticationclient.TokenReviewInterface, error) {
+ clientConfig, err := s.getClientConfig()
+ if err != nil {
+ return nil, err
+ }
+ client, err := authenticationclient.NewForConfig(clientConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ return client.TokenReviews(), nil
+}
+
+type ignorableError struct{ error }
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/authorization.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/authorization.go
new file mode 100644
index 0000000..a845921
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/authorization.go
@@ -0,0 +1,141 @@
+/*
+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 options
+
+import (
+ "time"
+
+ "github.com/spf13/pflag"
+
+ "k8s.io/apiserver/pkg/authorization/authorizerfactory"
+ "k8s.io/apiserver/pkg/server"
+ authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1beta1"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+)
+
+// DelegatingAuthorizationOptions provides an easy way for composing API servers to delegate their authorization to
+// the root kube API server.
+// WARNING: never assume that every authenticated incoming request already does authorization.
+// The aggregator in the kube API server does this today, but this behaviour is not
+// guaranteed in the future.
+type DelegatingAuthorizationOptions struct {
+ // RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the
+ // SubjectAccessReview.authorization.k8s.io endpoint for checking tokens.
+ RemoteKubeConfigFile string
+
+ // AllowCacheTTL is the length of time that a successful authorization response will be cached
+ AllowCacheTTL time.Duration
+
+ // DenyCacheTTL is the length of time that an unsuccessful authorization response will be cached.
+ // You generally want more responsive, "deny, try again" flows.
+ DenyCacheTTL time.Duration
+}
+
+func NewDelegatingAuthorizationOptions() *DelegatingAuthorizationOptions {
+ return &DelegatingAuthorizationOptions{
+ // very low for responsiveness, but high enough to handle storms
+ AllowCacheTTL: 10 * time.Second,
+ DenyCacheTTL: 10 * time.Second,
+ }
+}
+
+func (s *DelegatingAuthorizationOptions) Validate() []error {
+ allErrors := []error{}
+ return allErrors
+}
+
+func (s *DelegatingAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
+ if s == nil {
+ return
+ }
+
+ fs.StringVar(&s.RemoteKubeConfigFile, "authorization-kubeconfig", s.RemoteKubeConfigFile, ""+
+ "kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
+ " subjectaccessreviews.authorization.k8s.io.")
+
+ fs.DurationVar(&s.AllowCacheTTL, "authorization-webhook-cache-authorized-ttl",
+ s.AllowCacheTTL,
+ "The duration to cache 'authorized' responses from the webhook authorizer.")
+
+ fs.DurationVar(&s.DenyCacheTTL,
+ "authorization-webhook-cache-unauthorized-ttl", s.DenyCacheTTL,
+ "The duration to cache 'unauthorized' responses from the webhook authorizer.")
+}
+
+func (s *DelegatingAuthorizationOptions) ApplyTo(c *server.AuthorizationInfo) error {
+ if s == nil {
+ c.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
+ return nil
+ }
+
+ cfg, err := s.ToAuthorizationConfig()
+ if err != nil {
+ return err
+ }
+ authorizer, err := cfg.New()
+ if err != nil {
+ return err
+ }
+
+ c.Authorizer = authorizer
+ return nil
+}
+
+func (s *DelegatingAuthorizationOptions) ToAuthorizationConfig() (authorizerfactory.DelegatingAuthorizerConfig, error) {
+ sarClient, err := s.newSubjectAccessReview()
+ if err != nil {
+ return authorizerfactory.DelegatingAuthorizerConfig{}, err
+ }
+
+ ret := authorizerfactory.DelegatingAuthorizerConfig{
+ SubjectAccessReviewClient: sarClient,
+ AllowCacheTTL: s.AllowCacheTTL,
+ DenyCacheTTL: s.DenyCacheTTL,
+ }
+ return ret, nil
+}
+
+func (s *DelegatingAuthorizationOptions) newSubjectAccessReview() (authorizationclient.SubjectAccessReviewInterface, error) {
+ var clientConfig *rest.Config
+ var err error
+ if len(s.RemoteKubeConfigFile) > 0 {
+ loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile}
+ loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
+
+ clientConfig, err = loader.ClientConfig()
+
+ } else {
+ // without the remote kubeconfig file, try to use the in-cluster config. Most addon API servers will
+ // use this path
+ clientConfig, err = rest.InClusterConfig()
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ // set high qps/burst limits since this will effectively limit API server responsiveness
+ clientConfig.QPS = 200
+ clientConfig.Burst = 400
+
+ client, err := authorizationclient.NewForConfig(clientConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ return client.SubjectAccessReviews(), nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/coreapi.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/coreapi.go
new file mode 100644
index 0000000..d46dece
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/coreapi.go
@@ -0,0 +1,84 @@
+/*
+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 options
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/spf13/pflag"
+ "k8s.io/apiserver/pkg/server"
+ clientgoinformers "k8s.io/client-go/informers"
+ clientgoclientset "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+)
+
+// CoreAPIOptions contains options to configure the connection to a core API Kubernetes apiserver.
+type CoreAPIOptions struct {
+ // CoreAPIKubeconfigPath is a filename for a kubeconfig file to contact the core API server with.
+ // If it is not set, the in cluster config is used.
+ CoreAPIKubeconfigPath string
+}
+
+func NewCoreAPIOptions() *CoreAPIOptions {
+ return &CoreAPIOptions{}
+}
+
+func (o *CoreAPIOptions) AddFlags(fs *pflag.FlagSet) {
+ if o == nil {
+ return
+ }
+
+ fs.StringVar(&o.CoreAPIKubeconfigPath, "kubeconfig", o.CoreAPIKubeconfigPath,
+ "kubeconfig file pointing at the 'core' kubernetes server.")
+}
+
+func (o *CoreAPIOptions) ApplyTo(config *server.RecommendedConfig) error {
+ if o == nil {
+ return nil
+ }
+
+ // create shared informer for Kubernetes APIs
+ var kubeconfig *rest.Config
+ var err error
+ if len(o.CoreAPIKubeconfigPath) > 0 {
+ loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: o.CoreAPIKubeconfigPath}
+ loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
+ kubeconfig, err = loader.ClientConfig()
+ if err != nil {
+ return fmt.Errorf("failed to load kubeconfig at %q: %v", o.CoreAPIKubeconfigPath, err)
+ }
+ } else {
+ kubeconfig, err = rest.InClusterConfig()
+ if err != nil {
+ return err
+ }
+ }
+ clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeconfig)
+ if err != nil {
+ return fmt.Errorf("failed to create Kubernetes clientset: %v", err)
+ }
+ config.ClientConfig = kubeconfig
+ config.SharedInformerFactory = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)
+
+ return nil
+}
+
+func (o *CoreAPIOptions) Validate() []error {
+ return nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/doc.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/doc.go
new file mode 100644
index 0000000..426336b
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/doc.go
@@ -0,0 +1,21 @@
+/*
+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 options is the public flags and options used by a generic api
+// server. It takes a minimal set of dependencies and does not reference
+// implementations, in order to ensure it may be reused by multiple components
+// (such as CLI commands that wish to generate or validate config).
+package options // import "k8s.io/apiserver/pkg/server/options"
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/etcd.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/etcd.go
new file mode 100644
index 0000000..36f5ff5
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/etcd.go
@@ -0,0 +1,304 @@
+/*
+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 options
+
+import (
+ "fmt"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/spf13/pflag"
+
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apiserver/pkg/registry/generic"
+ genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
+ "k8s.io/apiserver/pkg/server"
+ "k8s.io/apiserver/pkg/server/healthz"
+ serverstorage "k8s.io/apiserver/pkg/server/storage"
+ "k8s.io/apiserver/pkg/storage/etcd3/preflight"
+ "k8s.io/apiserver/pkg/storage/storagebackend"
+)
+
+type EtcdOptions struct {
+ // The value of Paging on StorageConfig will be overridden by the
+ // calculated feature gate value.
+ StorageConfig storagebackend.Config
+ EncryptionProviderConfigFilepath string
+
+ EtcdServersOverrides []string
+
+ // To enable protobuf as storage format, it is enough
+ // to set it to "application/vnd.kubernetes.protobuf".
+ DefaultStorageMediaType string
+ DeleteCollectionWorkers int
+ EnableGarbageCollection bool
+
+ // Set EnableWatchCache to false to disable all watch caches
+ EnableWatchCache bool
+ // Set DefaultWatchCacheSize to zero to disable watch caches for those resources that have no explicit cache size set
+ DefaultWatchCacheSize int
+ // WatchCacheSizes represents override to a given resource
+ WatchCacheSizes []string
+}
+
+var storageTypes = sets.NewString(
+ storagebackend.StorageTypeUnset,
+ storagebackend.StorageTypeETCD2,
+ storagebackend.StorageTypeETCD3,
+)
+
+func NewEtcdOptions(backendConfig *storagebackend.Config) *EtcdOptions {
+ options := &EtcdOptions{
+ StorageConfig: *backendConfig,
+ DefaultStorageMediaType: "application/json",
+ DeleteCollectionWorkers: 1,
+ EnableGarbageCollection: true,
+ EnableWatchCache: true,
+ DefaultWatchCacheSize: 100,
+ }
+ options.StorageConfig.CountMetricPollPeriod = time.Minute
+ return options
+}
+
+func (s *EtcdOptions) Validate() []error {
+ if s == nil {
+ return nil
+ }
+
+ allErrors := []error{}
+ if len(s.StorageConfig.ServerList) == 0 {
+ allErrors = append(allErrors, fmt.Errorf("--etcd-servers must be specified"))
+ }
+
+ if !storageTypes.Has(s.StorageConfig.Type) {
+ allErrors = append(allErrors, fmt.Errorf("--storage-backend invalid, must be 'etcd3' or 'etcd2'. If not specified, it will default to 'etcd3'"))
+ }
+
+ for _, override := range s.EtcdServersOverrides {
+ tokens := strings.Split(override, "#")
+ if len(tokens) != 2 {
+ allErrors = append(allErrors, fmt.Errorf("--etcd-servers-overrides invalid, must be of format: group/resource#servers, where servers are URLs, semicolon separated"))
+ continue
+ }
+
+ apiresource := strings.Split(tokens[0], "/")
+ if len(apiresource) != 2 {
+ allErrors = append(allErrors, fmt.Errorf("--etcd-servers-overrides invalid, must be of format: group/resource#servers, where servers are URLs, semicolon separated"))
+ continue
+ }
+
+ }
+
+ return allErrors
+}
+
+// AddEtcdFlags adds flags related to etcd storage for a specific APIServer to the specified FlagSet
+func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
+ if s == nil {
+ return
+ }
+
+ fs.StringSliceVar(&s.EtcdServersOverrides, "etcd-servers-overrides", s.EtcdServersOverrides, ""+
+ "Per-resource etcd servers overrides, comma separated. The individual override "+
+ "format: group/resource#servers, where servers are URLs, semicolon separated.")
+
+ fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
+ "The media type to use to store objects in storage. "+
+ "Some resources or storage backends may only support a specific media type and will ignore this setting.")
+ fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
+ "Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.")
+
+ fs.BoolVar(&s.EnableGarbageCollection, "enable-garbage-collector", s.EnableGarbageCollection, ""+
+ "Enables the generic garbage collector. MUST be synced with the corresponding flag "+
+ "of the kube-controller-manager.")
+
+ fs.BoolVar(&s.EnableWatchCache, "watch-cache", s.EnableWatchCache,
+ "Enable watch caching in the apiserver")
+
+ fs.IntVar(&s.DefaultWatchCacheSize, "default-watch-cache-size", s.DefaultWatchCacheSize,
+ "Default watch cache size. If zero, watch cache will be disabled for resources that do not have a default watch size set.")
+
+ fs.StringSliceVar(&s.WatchCacheSizes, "watch-cache-sizes", s.WatchCacheSizes, ""+
+ "List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. "+
+ "The individual override format: resource[.group]#size, where resource is lowercase plural (no version), "+
+ "group is optional, and size is a number. It takes effect when watch-cache is enabled. "+
+ "Some resources (replicationcontrollers, endpoints, nodes, pods, services, apiservices.apiregistration.k8s.io) "+
+ "have system defaults set by heuristics, others default to default-watch-cache-size")
+
+ fs.StringVar(&s.StorageConfig.Type, "storage-backend", s.StorageConfig.Type,
+ "The storage backend for persistence. Options: 'etcd3' (default), 'etcd2'.")
+
+ fs.IntVar(&s.StorageConfig.DeserializationCacheSize, "deserialization-cache-size", s.StorageConfig.DeserializationCacheSize,
+ "Number of deserialized json objects to cache in memory.")
+
+ fs.StringSliceVar(&s.StorageConfig.ServerList, "etcd-servers", s.StorageConfig.ServerList,
+ "List of etcd servers to connect with (scheme://ip:port), comma separated.")
+
+ fs.StringVar(&s.StorageConfig.Prefix, "etcd-prefix", s.StorageConfig.Prefix,
+ "The prefix to prepend to all resource paths in etcd.")
+
+ fs.StringVar(&s.StorageConfig.KeyFile, "etcd-keyfile", s.StorageConfig.KeyFile,
+ "SSL key file used to secure etcd communication.")
+
+ fs.StringVar(&s.StorageConfig.CertFile, "etcd-certfile", s.StorageConfig.CertFile,
+ "SSL certification file used to secure etcd communication.")
+
+ fs.StringVar(&s.StorageConfig.CAFile, "etcd-cafile", s.StorageConfig.CAFile,
+ "SSL Certificate Authority file used to secure etcd communication.")
+
+ fs.BoolVar(&s.StorageConfig.Quorum, "etcd-quorum-read", s.StorageConfig.Quorum,
+ "If true, enable quorum read. It defaults to true and is strongly recommended not setting to false.")
+ fs.MarkDeprecated("etcd-quorum-read", "This flag is deprecated and the ability to switch off quorum read will be removed in a future release.")
+
+ fs.StringVar(&s.EncryptionProviderConfigFilepath, "experimental-encryption-provider-config", s.EncryptionProviderConfigFilepath,
+ "The file containing configuration for encryption providers to be used for storing secrets in etcd")
+
+ fs.DurationVar(&s.StorageConfig.CompactionInterval, "etcd-compaction-interval", s.StorageConfig.CompactionInterval,
+ "The interval of compaction requests. If 0, the compaction request from apiserver is disabled.")
+
+ fs.DurationVar(&s.StorageConfig.CountMetricPollPeriod, "etcd-count-metric-poll-period", s.StorageConfig.CountMetricPollPeriod, ""+
+ "Frequency of polling etcd for number of resources per type. 0 disables the metric collection.")
+}
+
+func (s *EtcdOptions) ApplyTo(c *server.Config) error {
+ if s == nil {
+ return nil
+ }
+
+ s.addEtcdHealthEndpoint(c)
+ c.RESTOptionsGetter = &SimpleRestOptionsFactory{Options: *s}
+ return nil
+}
+
+func (s *EtcdOptions) ApplyWithStorageFactoryTo(factory serverstorage.StorageFactory, c *server.Config) error {
+ s.addEtcdHealthEndpoint(c)
+ c.RESTOptionsGetter = &storageFactoryRestOptionsFactory{Options: *s, StorageFactory: factory}
+ return nil
+}
+
+func (s *EtcdOptions) addEtcdHealthEndpoint(c *server.Config) {
+ c.HealthzChecks = append(c.HealthzChecks, healthz.NamedCheck("etcd", func(r *http.Request) error {
+ done, err := preflight.EtcdConnection{ServerList: s.StorageConfig.ServerList}.CheckEtcdServers()
+ if !done {
+ return fmt.Errorf("etcd failed")
+ }
+ if err != nil {
+ return err
+ }
+ return nil
+ }))
+}
+
+type SimpleRestOptionsFactory struct {
+ Options EtcdOptions
+}
+
+func (f *SimpleRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
+ ret := generic.RESTOptions{
+ StorageConfig: &f.Options.StorageConfig,
+ Decorator: generic.UndecoratedStorage,
+ EnableGarbageCollection: f.Options.EnableGarbageCollection,
+ DeleteCollectionWorkers: f.Options.DeleteCollectionWorkers,
+ ResourcePrefix: resource.Group + "/" + resource.Resource,
+ CountMetricPollPeriod: f.Options.StorageConfig.CountMetricPollPeriod,
+ }
+ if f.Options.EnableWatchCache {
+ sizes, err := ParseWatchCacheSizes(f.Options.WatchCacheSizes)
+ if err != nil {
+ return generic.RESTOptions{}, err
+ }
+ cacheSize, ok := sizes[resource]
+ if !ok {
+ cacheSize = f.Options.DefaultWatchCacheSize
+ }
+ ret.Decorator = genericregistry.StorageWithCacher(cacheSize)
+ }
+ return ret, nil
+}
+
+type storageFactoryRestOptionsFactory struct {
+ Options EtcdOptions
+ StorageFactory serverstorage.StorageFactory
+}
+
+func (f *storageFactoryRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
+ storageConfig, err := f.StorageFactory.NewConfig(resource)
+ if err != nil {
+ return generic.RESTOptions{}, fmt.Errorf("unable to find storage destination for %v, due to %v", resource, err.Error())
+ }
+
+ ret := generic.RESTOptions{
+ StorageConfig: storageConfig,
+ Decorator: generic.UndecoratedStorage,
+ DeleteCollectionWorkers: f.Options.DeleteCollectionWorkers,
+ EnableGarbageCollection: f.Options.EnableGarbageCollection,
+ ResourcePrefix: f.StorageFactory.ResourcePrefix(resource),
+ CountMetricPollPeriod: f.Options.StorageConfig.CountMetricPollPeriod,
+ }
+ if f.Options.EnableWatchCache {
+ sizes, err := ParseWatchCacheSizes(f.Options.WatchCacheSizes)
+ if err != nil {
+ return generic.RESTOptions{}, err
+ }
+ cacheSize, ok := sizes[resource]
+ if !ok {
+ cacheSize = f.Options.DefaultWatchCacheSize
+ }
+ ret.Decorator = genericregistry.StorageWithCacher(cacheSize)
+ }
+
+ return ret, nil
+}
+
+// ParseWatchCacheSizes turns a list of cache size values into a map of group resources
+// to requested sizes.
+func ParseWatchCacheSizes(cacheSizes []string) (map[schema.GroupResource]int, error) {
+ watchCacheSizes := make(map[schema.GroupResource]int)
+ for _, c := range cacheSizes {
+ tokens := strings.Split(c, "#")
+ if len(tokens) != 2 {
+ return nil, fmt.Errorf("invalid value of watch cache size: %s", c)
+ }
+
+ size, err := strconv.Atoi(tokens[1])
+ if err != nil {
+ return nil, fmt.Errorf("invalid size of watch cache size: %s", c)
+ }
+ if size < 0 {
+ return nil, fmt.Errorf("watch cache size cannot be negative: %s", c)
+ }
+
+ watchCacheSizes[schema.ParseGroupResource(tokens[0])] = size
+ }
+ return watchCacheSizes, nil
+}
+
+// WriteWatchCacheSizes turns a map of cache size values into a list of string specifications.
+func WriteWatchCacheSizes(watchCacheSizes map[schema.GroupResource]int) ([]string, error) {
+ var cacheSizes []string
+
+ for resource, size := range watchCacheSizes {
+ if size < 0 {
+ return nil, fmt.Errorf("watch cache size cannot be negative for resource %s", resource)
+ }
+ cacheSizes = append(cacheSizes, fmt.Sprintf("%s#%d", resource.String(), size))
+ }
+ return cacheSizes, nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/feature.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/feature.go
new file mode 100644
index 0000000..7e02a18
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/feature.go
@@ -0,0 +1,74 @@
+/*
+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 options
+
+import (
+ "github.com/spf13/pflag"
+
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/apiserver/pkg/server"
+)
+
+type FeatureOptions struct {
+ EnableProfiling bool
+ EnableContentionProfiling bool
+ EnableSwaggerUI bool
+}
+
+func NewFeatureOptions() *FeatureOptions {
+ defaults := server.NewConfig(serializer.CodecFactory{})
+
+ return &FeatureOptions{
+ EnableProfiling: defaults.EnableProfiling,
+ EnableContentionProfiling: defaults.EnableContentionProfiling,
+ EnableSwaggerUI: defaults.EnableSwaggerUI,
+ }
+}
+
+func (o *FeatureOptions) AddFlags(fs *pflag.FlagSet) {
+ if o == nil {
+ return
+ }
+
+ fs.BoolVar(&o.EnableProfiling, "profiling", o.EnableProfiling,
+ "Enable profiling via web interface host:port/debug/pprof/")
+ fs.BoolVar(&o.EnableContentionProfiling, "contention-profiling", o.EnableContentionProfiling,
+ "Enable lock contention profiling, if profiling is enabled")
+ fs.BoolVar(&o.EnableSwaggerUI, "enable-swagger-ui", o.EnableSwaggerUI,
+ "Enables swagger ui on the apiserver at /swagger-ui")
+}
+
+func (o *FeatureOptions) ApplyTo(c *server.Config) error {
+ if o == nil {
+ return nil
+ }
+
+ c.EnableProfiling = o.EnableProfiling
+ c.EnableContentionProfiling = o.EnableContentionProfiling
+ c.EnableSwaggerUI = o.EnableSwaggerUI
+
+ return nil
+}
+
+func (o *FeatureOptions) Validate() []error {
+ if o == nil {
+ return nil
+ }
+
+ errs := []error{}
+ return errs
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/recommended.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/recommended.go
new file mode 100644
index 0000000..ebd750c
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/recommended.go
@@ -0,0 +1,125 @@
+/*
+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 options
+
+import (
+ "github.com/spf13/pflag"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apiserver/pkg/admission"
+ "k8s.io/apiserver/pkg/server"
+ "k8s.io/apiserver/pkg/storage/storagebackend"
+)
+
+// RecommendedOptions contains the recommended options for running an API server.
+// If you add something to this list, it should be in a logical grouping.
+// Each of them can be nil to leave the feature unconfigured on ApplyTo.
+type RecommendedOptions struct {
+ Etcd *EtcdOptions
+ SecureServing *SecureServingOptionsWithLoopback
+ Authentication *DelegatingAuthenticationOptions
+ Authorization *DelegatingAuthorizationOptions
+ Audit *AuditOptions
+ Features *FeatureOptions
+ CoreAPI *CoreAPIOptions
+
+ // ExtraAdmissionInitializers is called once after all ApplyTo from the options above, to pass the returned
+ // admission plugin initializers to Admission.ApplyTo.
+ ExtraAdmissionInitializers func(c *server.RecommendedConfig) ([]admission.PluginInitializer, error)
+ Admission *AdmissionOptions
+}
+
+func NewRecommendedOptions(prefix string, codec runtime.Codec) *RecommendedOptions {
+ sso := NewSecureServingOptions()
+
+ // We are composing recommended options for an aggregated api-server,
+ // whose client is typically a proxy multiplexing many operations ---
+ // notably including long-running ones --- into one HTTP/2 connection
+ // into this server. So allow many concurrent operations.
+ sso.HTTP2MaxStreamsPerConnection = 1000
+
+ return &RecommendedOptions{
+ Etcd: NewEtcdOptions(storagebackend.NewDefaultConfig(prefix, codec)),
+ SecureServing: WithLoopback(sso),
+ Authentication: NewDelegatingAuthenticationOptions(),
+ Authorization: NewDelegatingAuthorizationOptions(),
+ Audit: NewAuditOptions(),
+ Features: NewFeatureOptions(),
+ CoreAPI: NewCoreAPIOptions(),
+ ExtraAdmissionInitializers: func(c *server.RecommendedConfig) ([]admission.PluginInitializer, error) { return nil, nil },
+ Admission: NewAdmissionOptions(),
+ }
+}
+
+func (o *RecommendedOptions) AddFlags(fs *pflag.FlagSet) {
+ o.Etcd.AddFlags(fs)
+ o.SecureServing.AddFlags(fs)
+ o.Authentication.AddFlags(fs)
+ o.Authorization.AddFlags(fs)
+ o.Audit.AddFlags(fs)
+ o.Features.AddFlags(fs)
+ o.CoreAPI.AddFlags(fs)
+ o.Admission.AddFlags(fs)
+}
+
+// ApplyTo adds RecommendedOptions to the server configuration.
+// scheme is the scheme of the apiserver types that are sent to the admission chain.
+// pluginInitializers can be empty, it is only need for additional initializers.
+func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig, scheme *runtime.Scheme) error {
+ if err := o.Etcd.ApplyTo(&config.Config); err != nil {
+ return err
+ }
+ if err := o.SecureServing.ApplyTo(&config.Config); err != nil {
+ return err
+ }
+ if err := o.Authentication.ApplyTo(&config.Config.Authentication, config.SecureServing, config.OpenAPIConfig); err != nil {
+ return err
+ }
+ if err := o.Authorization.ApplyTo(&config.Config.Authorization); err != nil {
+ return err
+ }
+ if err := o.Audit.ApplyTo(&config.Config); err != nil {
+ return err
+ }
+ if err := o.Features.ApplyTo(&config.Config); err != nil {
+ return err
+ }
+ if err := o.CoreAPI.ApplyTo(config); err != nil {
+ return err
+ }
+ if initializers, err := o.ExtraAdmissionInitializers(config); err != nil {
+ return err
+ } else if err := o.Admission.ApplyTo(&config.Config, config.SharedInformerFactory, config.ClientConfig, scheme, initializers...); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (o *RecommendedOptions) Validate() []error {
+ errors := []error{}
+ errors = append(errors, o.Etcd.Validate()...)
+ errors = append(errors, o.SecureServing.Validate()...)
+ errors = append(errors, o.Authentication.Validate()...)
+ errors = append(errors, o.Authorization.Validate()...)
+ errors = append(errors, o.Audit.Validate()...)
+ errors = append(errors, o.Features.Validate()...)
+ errors = append(errors, o.CoreAPI.Validate()...)
+ errors = append(errors, o.Admission.Validate()...)
+
+ return errors
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
new file mode 100644
index 0000000..fccb24e
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
@@ -0,0 +1,158 @@
+/*
+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 options
+
+import (
+ "fmt"
+ "net"
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/apiserver/pkg/server"
+ utilfeature "k8s.io/apiserver/pkg/util/feature"
+
+ // add the generic feature gates
+ _ "k8s.io/apiserver/pkg/features"
+
+ "github.com/spf13/pflag"
+)
+
+// ServerRunOptions contains the options while running a generic api server.
+type ServerRunOptions struct {
+ AdvertiseAddress net.IP
+
+ CorsAllowedOriginList []string
+ ExternalHost string
+ MaxRequestsInFlight int
+ MaxMutatingRequestsInFlight int
+ RequestTimeout time.Duration
+ MinRequestTimeout int
+ TargetRAMMB int
+}
+
+func NewServerRunOptions() *ServerRunOptions {
+ defaults := server.NewConfig(serializer.CodecFactory{})
+ return &ServerRunOptions{
+ MaxRequestsInFlight: defaults.MaxRequestsInFlight,
+ MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight,
+ RequestTimeout: defaults.RequestTimeout,
+ MinRequestTimeout: defaults.MinRequestTimeout,
+ }
+}
+
+// ApplyOptions applies the run options to the method receiver and returns self
+func (s *ServerRunOptions) ApplyTo(c *server.Config) error {
+ c.CorsAllowedOriginList = s.CorsAllowedOriginList
+ c.ExternalAddress = s.ExternalHost
+ c.MaxRequestsInFlight = s.MaxRequestsInFlight
+ c.MaxMutatingRequestsInFlight = s.MaxMutatingRequestsInFlight
+ c.RequestTimeout = s.RequestTimeout
+ c.MinRequestTimeout = s.MinRequestTimeout
+ c.PublicAddress = s.AdvertiseAddress
+
+ return nil
+}
+
+// DefaultAdvertiseAddress sets the field AdvertiseAddress if unset. The field will be set based on the SecureServingOptions.
+func (s *ServerRunOptions) DefaultAdvertiseAddress(secure *SecureServingOptions) error {
+ if secure == nil {
+ return nil
+ }
+
+ if s.AdvertiseAddress == nil || s.AdvertiseAddress.IsUnspecified() {
+ hostIP, err := secure.DefaultExternalAddress()
+ if err != nil {
+ return fmt.Errorf("Unable to find suitable network address.error='%v'. "+
+ "Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err)
+ }
+ s.AdvertiseAddress = hostIP
+ }
+
+ return nil
+}
+
+// Validate checks validation of ServerRunOptions
+func (s *ServerRunOptions) Validate() []error {
+ errors := []error{}
+ if s.TargetRAMMB < 0 {
+ errors = append(errors, fmt.Errorf("--target-ram-mb can not be negative value"))
+ }
+ if s.MaxRequestsInFlight < 0 {
+ errors = append(errors, fmt.Errorf("--max-requests-inflight can not be negative value"))
+ }
+ if s.MaxMutatingRequestsInFlight < 0 {
+ errors = append(errors, fmt.Errorf("--max-mutating-requests-inflight can not be negative value"))
+ }
+
+ if s.RequestTimeout.Nanoseconds() < 0 {
+ errors = append(errors, fmt.Errorf("--request-timeout can not be negative value"))
+ }
+
+ if s.MinRequestTimeout < 0 {
+ errors = append(errors, fmt.Errorf("--min-request-timeout can not be negative value"))
+ }
+
+ return errors
+}
+
+// AddFlags adds flags for a specific APIServer to the specified FlagSet
+func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
+ // Note: the weird ""+ in below lines seems to be the only way to get gofmt to
+ // arrange these text blocks sensibly. Grrr.
+
+ fs.IPVar(&s.AdvertiseAddress, "advertise-address", s.AdvertiseAddress, ""+
+ "The IP address on which to advertise the apiserver to members of the cluster. This "+
+ "address must be reachable by the rest of the cluster. If blank, the --bind-address "+
+ "will be used. If --bind-address is unspecified, the host's default interface will "+
+ "be used.")
+
+ fs.StringSliceVar(&s.CorsAllowedOriginList, "cors-allowed-origins", s.CorsAllowedOriginList, ""+
+ "List of allowed origins for CORS, comma separated. An allowed origin can be a regular "+
+ "expression to support subdomain matching. If this list is empty CORS will not be enabled.")
+
+ fs.IntVar(&s.TargetRAMMB, "target-ram-mb", s.TargetRAMMB,
+ "Memory limit for apiserver in MB (used to configure sizes of caches, etc.)")
+
+ fs.StringVar(&s.ExternalHost, "external-hostname", s.ExternalHost,
+ "The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs).")
+
+ deprecatedMasterServiceNamespace := metav1.NamespaceDefault
+ fs.StringVar(&deprecatedMasterServiceNamespace, "master-service-namespace", deprecatedMasterServiceNamespace, ""+
+ "DEPRECATED: the namespace from which the kubernetes master services should be injected into pods.")
+
+ fs.IntVar(&s.MaxRequestsInFlight, "max-requests-inflight", s.MaxRequestsInFlight, ""+
+ "The maximum number of non-mutating requests in flight at a given time. When the server exceeds this, "+
+ "it rejects requests. Zero for no limit.")
+
+ fs.IntVar(&s.MaxMutatingRequestsInFlight, "max-mutating-requests-inflight", s.MaxMutatingRequestsInFlight, ""+
+ "The maximum number of mutating requests in flight at a given time. When the server exceeds this, "+
+ "it rejects requests. Zero for no limit.")
+
+ fs.DurationVar(&s.RequestTimeout, "request-timeout", s.RequestTimeout, ""+
+ "An optional field indicating the duration a handler must keep a request open before timing "+
+ "it out. This is the default request timeout for requests but may be overridden by flags such as "+
+ "--min-request-timeout for specific types of requests.")
+
+ fs.IntVar(&s.MinRequestTimeout, "min-request-timeout", s.MinRequestTimeout, ""+
+ "An optional field indicating the minimum number of seconds a handler must keep "+
+ "a request open before timing it out. Currently only honored by the watch request "+
+ "handler, which picks a randomized value above this number as the connection timeout, "+
+ "to spread out load.")
+
+ utilfeature.DefaultFeatureGate.AddFlag(fs)
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/serving.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/serving.go
new file mode 100644
index 0000000..5d21da2
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/serving.go
@@ -0,0 +1,297 @@
+/*
+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 options
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net"
+ "path"
+ "strconv"
+ "strings"
+
+ "github.com/golang/glog"
+ "github.com/spf13/pflag"
+
+ utilnet "k8s.io/apimachinery/pkg/util/net"
+ "k8s.io/apiserver/pkg/server"
+ utilflag "k8s.io/apiserver/pkg/util/flag"
+ certutil "k8s.io/client-go/util/cert"
+)
+
+type SecureServingOptions struct {
+ BindAddress net.IP
+ // BindPort is ignored when Listener is set, will serve https even with 0.
+ BindPort int
+ // BindNetwork is the type of network to bind to - defaults to "tcp", accepts "tcp",
+ // "tcp4", and "tcp6".
+ BindNetwork string
+
+ // Listener is the secure server network listener.
+ // either Listener or BindAddress/BindPort/BindNetwork is set,
+ // if Listener is set, use it and omit BindAddress/BindPort/BindNetwork.
+ Listener net.Listener
+
+ // ServerCert is the TLS cert info for serving secure traffic
+ ServerCert GeneratableKeyCert
+ // SNICertKeys are named CertKeys for serving secure traffic with SNI support.
+ SNICertKeys []utilflag.NamedCertKey
+ // CipherSuites is the list of allowed cipher suites for the server.
+ // Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants).
+ CipherSuites []string
+ // MinTLSVersion is the minimum TLS version supported.
+ // Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants).
+ MinTLSVersion string
+
+ // HTTP2MaxStreamsPerConnection is the limit that the api server imposes on each client.
+ // A value of zero means to use the default provided by golang's HTTP/2 support.
+ HTTP2MaxStreamsPerConnection int
+}
+
+type CertKey struct {
+ // CertFile is a file containing a PEM-encoded certificate, and possibly the complete certificate chain
+ CertFile string
+ // KeyFile is a file containing a PEM-encoded private key for the certificate specified by CertFile
+ KeyFile string
+}
+
+type GeneratableKeyCert struct {
+ CertKey CertKey
+
+ // CertDirectory is a directory that will contain the certificates. If the cert and key aren't specifically set
+ // this will be used to derive a match with the "pair-name"
+ CertDirectory string
+ // PairName is the name which will be used with CertDirectory to make a cert and key names
+ // It becomes CertDirector/PairName.crt and CertDirector/PairName.key
+ PairName string
+}
+
+func NewSecureServingOptions() *SecureServingOptions {
+ return &SecureServingOptions{
+ BindAddress: net.ParseIP("0.0.0.0"),
+ BindPort: 443,
+ ServerCert: GeneratableKeyCert{
+ PairName: "apiserver",
+ CertDirectory: "apiserver.local.config/certificates",
+ },
+ }
+}
+
+func (s *SecureServingOptions) DefaultExternalAddress() (net.IP, error) {
+ return utilnet.ChooseBindAddress(s.BindAddress)
+}
+
+func (s *SecureServingOptions) Validate() []error {
+ if s == nil {
+ return nil
+ }
+
+ errors := []error{}
+
+ if s.BindPort < 0 || s.BindPort > 65535 {
+ errors = append(errors, fmt.Errorf("--secure-port %v must be between 0 and 65535, inclusive. 0 for turning off secure port", s.BindPort))
+ }
+
+ return errors
+}
+
+func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) {
+ if s == nil {
+ return
+ }
+
+ fs.IPVar(&s.BindAddress, "bind-address", s.BindAddress, ""+
+ "The IP address on which to listen for the --secure-port port. The "+
+ "associated interface(s) must be reachable by the rest of the cluster, and by CLI/web "+
+ "clients. If blank, all interfaces will be used (0.0.0.0 for all IPv4 interfaces and :: for all IPv6 interfaces).")
+ fs.IntVar(&s.BindPort, "secure-port", s.BindPort, ""+
+ "The port on which to serve HTTPS with authentication and authorization. If 0, "+
+ "don't serve HTTPS at all.")
+
+ fs.StringVar(&s.ServerCert.CertDirectory, "cert-dir", s.ServerCert.CertDirectory, ""+
+ "The directory where the TLS certs are located. "+
+ "If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored.")
+
+ fs.StringVar(&s.ServerCert.CertKey.CertFile, "tls-cert-file", s.ServerCert.CertKey.CertFile, ""+
+ "File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated "+
+ "after server cert). If HTTPS serving is enabled, and --tls-cert-file and "+
+ "--tls-private-key-file are not provided, a self-signed certificate and key "+
+ "are generated for the public address and saved to the directory specified by --cert-dir.")
+
+ fs.StringVar(&s.ServerCert.CertKey.KeyFile, "tls-private-key-file", s.ServerCert.CertKey.KeyFile,
+ "File containing the default x509 private key matching --tls-cert-file.")
+
+ tlsCipherPossibleValues := utilflag.TLSCipherPossibleValues()
+ fs.StringSliceVar(&s.CipherSuites, "tls-cipher-suites", s.CipherSuites,
+ "Comma-separated list of cipher suites for the server. "+
+ "If omitted, the default Go cipher suites will be use. "+
+ "Possible values: "+strings.Join(tlsCipherPossibleValues, ","))
+
+ tlsPossibleVersions := utilflag.TLSPossibleVersions()
+ fs.StringVar(&s.MinTLSVersion, "tls-min-version", s.MinTLSVersion,
+ "Minimum TLS version supported. "+
+ "Possible values: "+strings.Join(tlsPossibleVersions, ", "))
+
+ fs.Var(utilflag.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+
+ "A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+
+ "domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+
+ "segments. If no domain patterns are provided, the names of the certificate are "+
+ "extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns "+
+ "trump over extracted names. For multiple key/certificate pairs, use the "+
+ "--tls-sni-cert-key multiple times. "+
+ "Examples: \"example.crt,example.key\" or \"foo.crt,foo.key:*.foo.com,foo.com\".")
+
+ fs.IntVar(&s.HTTP2MaxStreamsPerConnection, "http2-max-streams-per-connection", s.HTTP2MaxStreamsPerConnection, ""+
+ "The limit that the server gives to clients for "+
+ "the maximum number of streams in an HTTP/2 connection. "+
+ "Zero means to use golang's default.")
+}
+
+// ApplyTo fills up serving information in the server configuration.
+func (s *SecureServingOptions) ApplyTo(config **server.SecureServingInfo) error {
+ if s == nil {
+ return nil
+ }
+ if s.BindPort <= 0 && s.Listener == nil {
+ return nil
+ }
+
+ if s.Listener == nil {
+ var err error
+ addr := net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.BindPort))
+ s.Listener, s.BindPort, err = CreateListener(s.BindNetwork, addr)
+ if err != nil {
+ return fmt.Errorf("failed to create listener: %v", err)
+ }
+ } else {
+ if _, ok := s.Listener.Addr().(*net.TCPAddr); !ok {
+ return fmt.Errorf("failed to parse ip and port from listener")
+ }
+ s.BindPort = s.Listener.Addr().(*net.TCPAddr).Port
+ s.BindAddress = s.Listener.Addr().(*net.TCPAddr).IP
+ }
+
+ *config = &server.SecureServingInfo{
+ Listener: s.Listener,
+ HTTP2MaxStreamsPerConnection: s.HTTP2MaxStreamsPerConnection,
+ }
+ c := *config
+
+ serverCertFile, serverKeyFile := s.ServerCert.CertKey.CertFile, s.ServerCert.CertKey.KeyFile
+ // load main cert
+ if len(serverCertFile) != 0 || len(serverKeyFile) != 0 {
+ tlsCert, err := tls.LoadX509KeyPair(serverCertFile, serverKeyFile)
+ if err != nil {
+ return fmt.Errorf("unable to load server certificate: %v", err)
+ }
+ c.Cert = &tlsCert
+ }
+
+ if len(s.CipherSuites) != 0 {
+ cipherSuites, err := utilflag.TLSCipherSuites(s.CipherSuites)
+ if err != nil {
+ return err
+ }
+ c.CipherSuites = cipherSuites
+ }
+
+ var err error
+ c.MinTLSVersion, err = utilflag.TLSVersion(s.MinTLSVersion)
+ if err != nil {
+ return err
+ }
+
+ // load SNI certs
+ namedTLSCerts := make([]server.NamedTLSCert, 0, len(s.SNICertKeys))
+ for _, nck := range s.SNICertKeys {
+ tlsCert, err := tls.LoadX509KeyPair(nck.CertFile, nck.KeyFile)
+ namedTLSCerts = append(namedTLSCerts, server.NamedTLSCert{
+ TLSCert: tlsCert,
+ Names: nck.Names,
+ })
+ if err != nil {
+ return fmt.Errorf("failed to load SNI cert and key: %v", err)
+ }
+ }
+ c.SNICerts, err = server.GetNamedCertificateMap(namedTLSCerts)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (s *SecureServingOptions) MaybeDefaultWithSelfSignedCerts(publicAddress string, alternateDNS []string, alternateIPs []net.IP) error {
+ if s == nil {
+ return nil
+ }
+ keyCert := &s.ServerCert.CertKey
+ if len(keyCert.CertFile) != 0 || len(keyCert.KeyFile) != 0 {
+ return nil
+ }
+
+ keyCert.CertFile = path.Join(s.ServerCert.CertDirectory, s.ServerCert.PairName+".crt")
+ keyCert.KeyFile = path.Join(s.ServerCert.CertDirectory, s.ServerCert.PairName+".key")
+
+ canReadCertAndKey, err := certutil.CanReadCertAndKey(keyCert.CertFile, keyCert.KeyFile)
+ if err != nil {
+ return err
+ }
+ if !canReadCertAndKey {
+ // add either the bind address or localhost to the valid alternates
+ bindIP := s.BindAddress.String()
+ if bindIP == "0.0.0.0" {
+ alternateDNS = append(alternateDNS, "localhost")
+ } else {
+ alternateIPs = append(alternateIPs, s.BindAddress)
+ }
+
+ if cert, key, err := certutil.GenerateSelfSignedCertKey(publicAddress, alternateIPs, alternateDNS); err != nil {
+ return fmt.Errorf("unable to generate self signed cert: %v", err)
+ } else {
+ if err := certutil.WriteCert(keyCert.CertFile, cert); err != nil {
+ return err
+ }
+
+ if err := certutil.WriteKey(keyCert.KeyFile, key); err != nil {
+ return err
+ }
+ glog.Infof("Generated self-signed cert (%s, %s)", keyCert.CertFile, keyCert.KeyFile)
+ }
+ }
+
+ return nil
+}
+
+func CreateListener(network, addr string) (net.Listener, int, error) {
+ if len(network) == 0 {
+ network = "tcp"
+ }
+ ln, err := net.Listen(network, addr)
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to listen on %v: %v", addr, err)
+ }
+
+ // get port
+ tcpAddr, ok := ln.Addr().(*net.TCPAddr)
+ if !ok {
+ ln.Close()
+ return nil, 0, fmt.Errorf("invalid listen address: %q", ln.Addr().String())
+ }
+
+ return ln, tcpAddr.Port, nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go
new file mode 100644
index 0000000..8d249cb
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 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 options
+
+import (
+ "crypto/tls"
+ "fmt"
+
+ "github.com/pborman/uuid"
+
+ "k8s.io/apiserver/pkg/server"
+ certutil "k8s.io/client-go/util/cert"
+)
+
+type SecureServingOptionsWithLoopback struct {
+ *SecureServingOptions
+}
+
+func WithLoopback(o *SecureServingOptions) *SecureServingOptionsWithLoopback {
+ return &SecureServingOptionsWithLoopback{o}
+}
+
+// ApplyTo fills up serving information in the server configuration.
+func (s *SecureServingOptionsWithLoopback) ApplyTo(c *server.Config) error {
+ if s == nil || s.SecureServingOptions == nil {
+ return nil
+ }
+
+ if err := s.SecureServingOptions.ApplyTo(&c.SecureServing); err != nil {
+ return err
+ }
+
+ if c.SecureServing == nil {
+ return nil
+ }
+
+ c.ReadWritePort = s.BindPort
+
+ // create self-signed cert+key with the fake server.LoopbackClientServerNameOverride and
+ // let the server return it when the loopback client connects.
+ certPem, keyPem, err := certutil.GenerateSelfSignedCertKey(server.LoopbackClientServerNameOverride, nil, nil)
+ if err != nil {
+ return fmt.Errorf("failed to generate self-signed certificate for loopback connection: %v", err)
+ }
+ tlsCert, err := tls.X509KeyPair(certPem, keyPem)
+ if err != nil {
+ return fmt.Errorf("failed to generate self-signed certificate for loopback connection: %v", err)
+ }
+
+ secureLoopbackClientConfig, err := c.SecureServing.NewLoopbackClientConfig(uuid.NewRandom().String(), certPem)
+ switch {
+ // if we failed and there's no fallback loopback client config, we need to fail
+ case err != nil && c.LoopbackClientConfig == nil:
+ return err
+
+ // if we failed, but we already have a fallback loopback client config (usually insecure), allow it
+ case err != nil && c.LoopbackClientConfig != nil:
+
+ default:
+ c.LoopbackClientConfig = secureLoopbackClientConfig
+ c.SecureServing.SNICerts[server.LoopbackClientServerNameOverride] = &tlsCert
+ }
+
+ return nil
+}