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
+}