diff --git a/cmd/kube-apiserver/app/BUILD b/cmd/kube-apiserver/app/BUILD index 3388c4fb6ec87..b399c58248a79 100644 --- a/cmd/kube-apiserver/app/BUILD +++ b/cmd/kube-apiserver/app/BUILD @@ -85,6 +85,7 @@ go_library( "//vendor/k8s.io/apiserver/pkg/server/mux:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/options:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library", + "//vendor/k8s.io/client-go/informers:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/apiserver:go_default_library", diff --git a/cmd/kube-apiserver/app/options/options.go b/cmd/kube-apiserver/app/options/options.go index 736067c22501f..f3ce2fad017e1 100644 --- a/cmd/kube-apiserver/app/options/options.go +++ b/cmd/kube-apiserver/app/options/options.go @@ -112,6 +112,8 @@ func NewServerRunOptions() *ServerRunOptions { } // Overwrite the default for storage data format. s.Etcd.DefaultStorageMediaType = "application/vnd.kubernetes.protobuf" + // Set the default for admission plugins names + s.Admission.PluginNames = []string{"AlwaysAdmit"} return &s } diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 35915073c80e0..d5c8e7e7d543e 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -51,6 +51,8 @@ import ( "k8s.io/apiserver/pkg/server/filters" serverstorage "k8s.io/apiserver/pkg/server/storage" + clientgoinformers "k8s.io/client-go/informers" + clientgo "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/cmd/kube-apiserver/app/options" "k8s.io/kubernetes/cmd/kube-apiserver/app/preflight" "k8s.io/kubernetes/pkg/api" @@ -99,11 +101,11 @@ cluster's shared state through which all other components interact.`, // Run runs the specified APIServer. This should never exit. func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error { - kubeAPIServerConfig, sharedInformers, insecureServingOptions, err := CreateKubeAPIServerConfig(runOptions) + kubeAPIServerConfig, internalSharedInformers, externalSharedInformers, insecureServingOptions, err := CreateKubeAPIServerConfig(runOptions) if err != nil { return err } - kubeAPIServer, err := CreateKubeAPIServer(kubeAPIServerConfig, sharedInformers, stopCh) + kubeAPIServer, err := CreateKubeAPIServer(kubeAPIServerConfig, internalSharedInformers, externalSharedInformers, stopCh) if err != nil { return err } @@ -129,7 +131,7 @@ func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error { if err != nil { return err } - aggregatorServer, err := createAggregatorServer(aggregatorConfig, kubeAPIServer.GenericAPIServer, sharedInformers, stopCh) + aggregatorServer, err := createAggregatorServer(aggregatorConfig, kubeAPIServer.GenericAPIServer, internalSharedInformers, stopCh) if err != nil { // we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines return err @@ -138,13 +140,14 @@ func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error { } // CreateKubeAPIServer creates and wires a workable kube-apiserver -func CreateKubeAPIServer(kubeAPIServerConfig *master.Config, sharedInformers informers.SharedInformerFactory, stopCh <-chan struct{}) (*master.Master, error) { +func CreateKubeAPIServer(kubeAPIServerConfig *master.Config, internalSharedInformers informers.SharedInformerFactory, externalSharedInformers clientgoinformers.SharedInformerFactory, stopCh <-chan struct{}) (*master.Master, error) { kubeAPIServer, err := kubeAPIServerConfig.Complete().New() if err != nil { return nil, err } kubeAPIServer.GenericAPIServer.AddPostStartHook("start-kube-apiserver-informers", func(context genericapiserver.PostStartHookContext) error { - sharedInformers.Start(stopCh) + internalSharedInformers.Start(stopCh) + externalSharedInformers.Start(stopCh) return nil }) @@ -152,24 +155,24 @@ func CreateKubeAPIServer(kubeAPIServerConfig *master.Config, sharedInformers inf } // CreateKubeAPIServerConfig creates all the resources for running the API server, but runs none of them -func CreateKubeAPIServerConfig(s *options.ServerRunOptions) (*master.Config, informers.SharedInformerFactory, *kubeserver.InsecureServingInfo, error) { +func CreateKubeAPIServerConfig(s *options.ServerRunOptions) (*master.Config, informers.SharedInformerFactory, clientgoinformers.SharedInformerFactory, *kubeserver.InsecureServingInfo, error) { // set defaults in the options before trying to create the generic config if err := defaultOptions(s); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } // validate options if errs := s.Validate(); len(errs) != 0 { - return nil, nil, nil, utilerrors.NewAggregate(errs) + return nil, nil, nil, nil, utilerrors.NewAggregate(errs) } - genericConfig, sharedInformers, insecureServingOptions, err := BuildGenericConfig(s) + genericConfig, internalSharedInformerFactory, externalSharedInformerFactory, insecureServingOptions, err := BuildGenericConfig(s) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } if err := utilwait.PollImmediate(etcdRetryInterval, etcdRetryLimit*etcdRetryInterval, preflight.EtcdConnection{ServerList: s.Etcd.StorageConfig.ServerList}.CheckEtcdServers); err != nil { - return nil, nil, nil, fmt.Errorf("error waiting for etcd connection: %v", err) + return nil, nil, nil, nil, fmt.Errorf("error waiting for etcd connection: %v", err) } capabilities.Initialize(capabilities.Capabilities{ @@ -191,7 +194,7 @@ func CreateKubeAPIServerConfig(s *options.ServerRunOptions) (*master.Config, inf var installSSHKey tunneler.InstallSSHKey cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider.CloudProvider, s.CloudProvider.CloudConfigFile) if err != nil { - return nil, nil, nil, fmt.Errorf("cloud provider could not be initialized: %v", err) + return nil, nil, nil, nil, fmt.Errorf("cloud provider could not be initialized: %v", err) } if cloud != nil { if instances, supported := cloud.Instances(); supported { @@ -199,10 +202,10 @@ func CreateKubeAPIServerConfig(s *options.ServerRunOptions) (*master.Config, inf } } if s.KubeletConfig.Port == 0 { - return nil, nil, nil, fmt.Errorf("must enable kubelet port if proxy ssh-tunneling is specified") + return nil, nil, nil, nil, fmt.Errorf("must enable kubelet port if proxy ssh-tunneling is specified") } if s.KubeletConfig.ReadOnlyPort == 0 { - return nil, nil, nil, fmt.Errorf("must enable kubelet readonly port if proxy ssh-tunneling is specified") + return nil, nil, nil, nil, fmt.Errorf("must enable kubelet readonly port if proxy ssh-tunneling is specified") } // Set up the nodeTunneler // TODO(cjcullen): If we want this to handle per-kubelet ports or other @@ -228,21 +231,21 @@ func CreateKubeAPIServerConfig(s *options.ServerRunOptions) (*master.Config, inf serviceIPRange, apiServerServiceIP, err := master.DefaultServiceIPRange(s.ServiceClusterIPRange) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } storageFactory, err := BuildStorageFactory(s) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } clientCA, err := readCAorNil(s.Authentication.ClientCert.ClientCA) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } requestHeaderProxyCA, err := readCAorNil(s.Authentication.RequestHeader.ClientCAFile) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } config := &master.Config{ @@ -278,30 +281,30 @@ func CreateKubeAPIServerConfig(s *options.ServerRunOptions) (*master.Config, inf MasterCount: s.MasterCount, } - return config, sharedInformers, insecureServingOptions, nil + return config, internalSharedInformerFactory, externalSharedInformerFactory, insecureServingOptions, nil } // BuildGenericConfig takes the master server options and produces the genericapiserver.Config associated with it -func BuildGenericConfig(s *options.ServerRunOptions) (*genericapiserver.Config, informers.SharedInformerFactory, *kubeserver.InsecureServingInfo, error) { +func BuildGenericConfig(s *options.ServerRunOptions) (*genericapiserver.Config, informers.SharedInformerFactory, clientgoinformers.SharedInformerFactory, *kubeserver.InsecureServingInfo, error) { genericConfig := genericapiserver.NewConfig(api.Codecs) if err := s.GenericServerRunOptions.ApplyTo(genericConfig); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } insecureServingOptions, err := s.InsecureServing.ApplyTo(genericConfig) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } if err := s.SecureServing.ApplyTo(genericConfig); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } if err := s.Authentication.ApplyTo(genericConfig); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } if err := s.Audit.ApplyTo(genericConfig); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } if err := s.Features.ApplyTo(genericConfig); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, api.Scheme) @@ -319,10 +322,10 @@ func BuildGenericConfig(s *options.ServerRunOptions) (*genericapiserver.Config, storageFactory, err := BuildStorageFactory(s) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } if err := s.Etcd.ApplyWithStorageFactoryTo(storageFactory, genericConfig); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } // Use protobufs for self-communication. @@ -331,67 +334,80 @@ func BuildGenericConfig(s *options.ServerRunOptions) (*genericapiserver.Config, // set it in kube-apiserver. genericConfig.LoopbackClientConfig.ContentConfig.ContentType = "application/vnd.kubernetes.protobuf" - client, err := internalclientset.NewForConfig(genericConfig.LoopbackClientConfig) - if err != nil { - kubeAPIVersions := os.Getenv("KUBE_API_VERSIONS") - if len(kubeAPIVersions) == 0 { - return nil, nil, nil, fmt.Errorf("failed to create clientset: %v", err) - } + kubeAPIVersions := os.Getenv("KUBE_API_VERSIONS") + internalClient, intErr := internalclientset.NewForConfig(genericConfig.LoopbackClientConfig) + if intErr != nil && len(kubeAPIVersions) == 0 { + return nil, nil, nil, nil, fmt.Errorf("failed to create internal clientset: %v", intErr) + } + externalClient, extErr := clientgo.NewForConfig(genericConfig.LoopbackClientConfig) + if extErr != nil && len(kubeAPIVersions) == 0 { + return nil, nil, nil, nil, fmt.Errorf("failed to create external clientset: %v", extErr) + } + + if intErr != nil || extErr != nil { // KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API // groups. This leads to a nil client above and undefined behaviour further down. // // TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set - glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions) + glog.Errorf("Failed to create client with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions) } - sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute) - genericConfig.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, storageFactory, client, sharedInformers) + // create shared informers + internalSharedInformersFactory := informers.NewSharedInformerFactory(internalClient, 10*time.Minute) + externalSharedInformerFactory := clientgoinformers.NewSharedInformerFactory(externalClient, genericConfig.LoopbackClientConfig.Timeout) + + genericConfig.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, storageFactory, internalClient, internalSharedInformersFactory) if err != nil { - return nil, nil, nil, fmt.Errorf("invalid authentication config: %v", err) + return nil, nil, nil, nil, fmt.Errorf("invalid authentication config: %v", err) } - genericConfig.Authorizer, err = BuildAuthorizer(s, sharedInformers) + genericConfig.Authorizer, err = BuildAuthorizer(s, internalSharedInformersFactory) if err != nil { - return nil, nil, nil, fmt.Errorf("invalid authorization config: %v", err) + return nil, nil, nil, nil, fmt.Errorf("invalid authorization config: %v", err) } if !sets.NewString(s.Authorization.Modes()...).Has(modes.ModeRBAC) { genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName) } - genericConfig.AdmissionControl, err = BuildAdmission(s, - s.Admission.Plugins, - client, - sharedInformers, + pluginInitializer, err := BuildAdmissionPluginInitializer( + s, + internalClient, + internalSharedInformersFactory, genericConfig.Authorizer, ) if err != nil { - return nil, nil, nil, fmt.Errorf("failed to initialize admission: %v", err) + return nil, nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err) } - return genericConfig, sharedInformers, insecureServingOptions, nil + err = s.Admission.ApplyTo( + genericConfig.Authorizer, + genericConfig.LoopbackClientConfig, + genericConfig, + externalSharedInformerFactory, + pluginInitializer) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed to initialize admission: %v", err) + } + return genericConfig, internalSharedInformersFactory, externalSharedInformerFactory, insecureServingOptions, nil } -// BuildAdmission constructs the admission chain -func BuildAdmission(s *options.ServerRunOptions, plugins *admission.Plugins, client internalclientset.Interface, sharedInformers informers.SharedInformerFactory, apiAuthorizer authorizer.Authorizer) (admission.Interface, error) { - admissionControlPluginNames := strings.Split(s.Admission.Control, ",") +// BuildAdmissionPluginInitializer constructs the admission plugin initializer +func BuildAdmissionPluginInitializer(s *options.ServerRunOptions, client internalclientset.Interface, sharedInformers informers.SharedInformerFactory, apiAuthorizer authorizer.Authorizer) (admission.PluginInitializer, error) { var cloudConfig []byte - var err error if s.CloudProvider.CloudConfigFile != "" { + var err error cloudConfig, err = ioutil.ReadFile(s.CloudProvider.CloudConfigFile) if err != nil { glog.Fatalf("Error reading from cloud configuration file %s: %#v", s.CloudProvider.CloudConfigFile, err) } } + // TODO: use a dynamic restmapper. See https://github.com/kubernetes/kubernetes/pull/42615. restMapper := api.Registry.RESTMapper() pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer, cloudConfig, restMapper) - admissionConfigProvider, err := admission.ReadAdmissionConfiguration(admissionControlPluginNames, s.Admission.ControlConfigFile) - if err != nil { - return nil, fmt.Errorf("failed to read plugin config: %v", err) - } - return plugins.NewFromPlugins(admissionControlPluginNames, admissionConfigProvider, pluginInitializer) + return pluginInitializer, nil } // BuildAuthenticator constructs the authenticator diff --git a/federation/cmd/federation-apiserver/app/BUILD b/federation/cmd/federation-apiserver/app/BUILD index 2a8aab51e9e58..f9162eeb09773 100644 --- a/federation/cmd/federation-apiserver/app/BUILD +++ b/federation/cmd/federation-apiserver/app/BUILD @@ -75,12 +75,13 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", - "//vendor/k8s.io/apiserver/pkg/admission:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//vendor/k8s.io/apiserver/pkg/server:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/filters:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library", + "//vendor/k8s.io/client-go/informers:go_default_library", + "//vendor/k8s.io/client-go/kubernetes:go_default_library", ], ) diff --git a/federation/cmd/federation-apiserver/app/options/options.go b/federation/cmd/federation-apiserver/app/options/options.go index a2f49d491d1a5..b4d9292e50dc4 100644 --- a/federation/cmd/federation-apiserver/app/options/options.go +++ b/federation/cmd/federation-apiserver/app/options/options.go @@ -70,6 +70,8 @@ func NewServerRunOptions() *ServerRunOptions { } // Overwrite the default for storage data format. s.Etcd.DefaultStorageMediaType = "application/vnd.kubernetes.protobuf" + // Set the default for admission plugins names + s.Admission.PluginNames = []string{"AlwaysAdmit"} return &s } diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 8cea7ece4fbef..51752a6b4f8b6 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -34,10 +34,11 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apiserver/pkg/admission" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/filters" serverstorage "k8s.io/apiserver/pkg/server/storage" + clientgoinformers "k8s.io/client-go/informers" + clientgo "k8s.io/client-go/kubernetes" federationv1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1" "k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options" "k8s.io/kubernetes/pkg/api" @@ -173,33 +174,42 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { return fmt.Errorf("invalid Authentication Config: %v", err) } - client, err := internalclientset.NewForConfig(genericConfig.LoopbackClientConfig) + internalClient, err := internalclientset.NewForConfig(genericConfig.LoopbackClientConfig) if err != nil { - return fmt.Errorf("failed to create clientset: %v", err) + return fmt.Errorf("failed to create internal clientset: %v", err) } - sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute) - authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers) + externalClient, err := clientgo.NewForConfig(genericConfig.LoopbackClientConfig) + if err != nil { + return fmt.Errorf("failed to create external clientset: %v", err) + } + + internalSharedInformers := informers.NewSharedInformerFactory(internalClient, 10*time.Minute) + externalSharedInformers := clientgoinformers.NewSharedInformerFactory(externalClient, genericConfig.LoopbackClientConfig.Timeout) + + authorizationConfig := s.Authorization.ToAuthorizationConfig(internalSharedInformers) apiAuthorizer, err := authorizationConfig.New() if err != nil { return fmt.Errorf("invalid Authorization Config: %v", err) } - admissionControlPluginNames := strings.Split(s.Admission.Control, ",") var cloudConfig []byte - if s.CloudProvider.CloudConfigFile != "" { cloudConfig, err = ioutil.ReadFile(s.CloudProvider.CloudConfigFile) if err != nil { glog.Fatalf("Error reading from cloud configuration file %s: %#v", s.CloudProvider.CloudConfigFile, err) } } - pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer, cloudConfig, nil) - admissionConfigProvider, err := admission.ReadAdmissionConfiguration(admissionControlPluginNames, s.Admission.ControlConfigFile) - if err != nil { - return fmt.Errorf("failed to read plugin config: %v", err) - } - admissionController, err := kubeapiserveradmission.Plugins.NewFromPlugins(admissionControlPluginNames, admissionConfigProvider, pluginInitializer) + + pluginInitializer := kubeapiserveradmission.NewPluginInitializer(internalClient, internalSharedInformers, apiAuthorizer, cloudConfig, nil) + + err = s.Admission.ApplyTo( + apiAuthorizer, + genericConfig.LoopbackClientConfig, + genericConfig, + externalSharedInformers, + pluginInitializer, + ) if err != nil { return fmt.Errorf("failed to initialize plugins: %v", err) } @@ -208,7 +218,6 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { genericConfig.Version = &kubeVersion genericConfig.Authenticator = apiAuthenticator genericConfig.Authorizer = apiAuthorizer - genericConfig.AdmissionControl = admissionController genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapi.GetOpenAPIDefinitions, api.Scheme) genericConfig.OpenAPIConfig.PostProcessSpec = postProcessOpenAPISpecForBackwardCompatibility genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions @@ -249,7 +258,8 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error { err = m.PrepareRun().NonBlockingRun(stopCh) if err == nil { - sharedInformers.Start(stopCh) + internalSharedInformers.Start(stopCh) + externalSharedInformers.Start(stopCh) } return err } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/BUILD b/staging/src/k8s.io/apiserver/pkg/server/options/BUILD index 2ef511007f04b..dfbe858898239 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/server/options/BUILD @@ -53,7 +53,9 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission:go_default_library", + "//vendor/k8s.io/apiserver/pkg/admission/initializer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory:go_default_library", + "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library", "//vendor/k8s.io/apiserver/pkg/features:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", @@ -63,6 +65,8 @@ go_library( "//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library", + "//vendor/k8s.io/client-go/informers:go_default_library", + "//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go index 6f1774a72b198..aa8a40ef8f531 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go @@ -17,33 +17,75 @@ limitations under the License. package options import ( + "fmt" "strings" "github.com/spf13/pflag" "k8s.io/apiserver/pkg/admission" + "k8s.io/apiserver/pkg/admission/initializer" + "k8s.io/apiserver/pkg/authorization/authorizer" + "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" ) // AdmissionOptions holds the admission options type AdmissionOptions struct { - Control string - ControlConfigFile string - Plugins *admission.Plugins + PluginNames []string + ConfigFile string + Plugins *admission.Plugins + genericPluginInitializer admission.PluginInitializer } // NewAdmissionOptions creates a new instance of AdmissionOptions func NewAdmissionOptions(plugins *admission.Plugins) *AdmissionOptions { return &AdmissionOptions{ - Plugins: plugins, - Control: "AlwaysAdmit", + Plugins: plugins, + PluginNames: []string{}, + genericPluginInitializer: nil, } } // AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet func (a *AdmissionOptions) AddFlags(fs *pflag.FlagSet) { - fs.StringVar(&a.Control, "admission-control", a.Control, ""+ + fs.StringSliceVar(&a.PluginNames, "admission-control", a.PluginNames, ""+ "Ordered list of plug-ins to do admission control of resources into cluster. "+ "Comma-delimited list of: "+strings.Join(a.Plugins.Registered(), ", ")+".") - fs.StringVar(&a.ControlConfigFile, "admission-control-config-file", a.ControlConfigFile, + fs.StringVar(&a.ConfigFile, "admission-control-config-file", a.ConfigFile, "File with admission control configuration.") } + +// ApplyTo adds the admission chain to the server configuration +// the method lazily initializes a generic plugin that is appended to the list of pluginInitializers +func (a *AdmissionOptions) ApplyTo(authz authorizer.Authorizer, restConfig *rest.Config, serverCfg *server.Config, sharedInformers informers.SharedInformerFactory, pluginInitializers ...admission.PluginInitializer) error { + pluginsConfigProvider, err := admission.ReadAdmissionConfiguration(a.PluginNames, a.ConfigFile) + if err != nil { + return fmt.Errorf("failed to read plugin config: %v", err) + } + + // init generic plugin initalizer + if a.genericPluginInitializer == nil { + clientset, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return err + } + genericInitializer, err := initializer.New(clientset, sharedInformers, authz) + if err != nil { + return err + } + a.genericPluginInitializer = genericInitializer + } + + initializersChain := admission.PluginInitializers{} + pluginInitializers = append(pluginInitializers, a.genericPluginInitializer) + initializersChain = append(initializersChain, pluginInitializers...) + admissionChain, err := a.Plugins.NewFromPlugins(a.PluginNames, pluginsConfigProvider, initializersChain) + if err != nil { + return err + } + + serverCfg.AdmissionControl = admissionChain + return nil +} diff --git a/test/integration/etcd/etcd_storage_path_test.go b/test/integration/etcd/etcd_storage_path_test.go index 7256f7e7cb8a7..1566d8ec0b6a1 100644 --- a/test/integration/etcd/etcd_storage_path_test.go +++ b/test/integration/etcd/etcd_storage_path_test.go @@ -554,14 +554,14 @@ func startRealMasterOrDie(t *testing.T, certDir string) (*allClient, clientv3.KV kubeAPIServerOptions.SecureServing.BindPort = kubePort - kubeAPIServerConfig, sharedInformers, _, err := app.CreateKubeAPIServerConfig(kubeAPIServerOptions) + kubeAPIServerConfig, internalSharedInformers, externalSharedInformers, _, err := app.CreateKubeAPIServerConfig(kubeAPIServerOptions) if err != nil { t.Fatal(err) } kubeAPIServerConfig.APIResourceConfigSource = &allResourceSource{} // force enable all resources - kubeAPIServer, err := app.CreateKubeAPIServer(kubeAPIServerConfig, sharedInformers, wait.NeverStop) + kubeAPIServer, err := app.CreateKubeAPIServer(kubeAPIServerConfig, internalSharedInformers, externalSharedInformers, wait.NeverStop) if err != nil { t.Fatal(err) } diff --git a/test/integration/examples/apiserver_test.go b/test/integration/examples/apiserver_test.go index b468ee2bc6d3c..1f808e2a497ee 100644 --- a/test/integration/examples/apiserver_test.go +++ b/test/integration/examples/apiserver_test.go @@ -111,13 +111,13 @@ func TestAggregatedAPIServer(t *testing.T) { kubeAPIServerOptions.Authentication.ClientCert.ClientCA = clientCACertFile.Name() kubeAPIServerOptions.Authorization.Mode = "RBAC" - kubeAPIServerConfig, sharedInformers, _, err := app.CreateKubeAPIServerConfig(kubeAPIServerOptions) + kubeAPIServerConfig, internalSharedInformers, externalSharedInformers, _, err := app.CreateKubeAPIServerConfig(kubeAPIServerOptions) if err != nil { t.Fatal(err) } kubeClientConfigValue.Store(kubeAPIServerConfig.GenericConfig.LoopbackClientConfig) - kubeAPIServer, err := app.CreateKubeAPIServer(kubeAPIServerConfig, sharedInformers, wait.NeverStop) + kubeAPIServer, err := app.CreateKubeAPIServer(kubeAPIServerConfig, internalSharedInformers, externalSharedInformers, wait.NeverStop) if err != nil { t.Fatal(err) }