Merge pull request #45355 from p0lyn0mial/admission_options_spits_out_admission_control

Automatic merge from submit-queue (batch tested with PRs 45408, 45355, 45528)

Admission options spits out admission control

**What this PR does / why we need it**:

This PR adds ApplyTo method to AdmissionOptions struct. The method creates and initialises admission control to the server configuration.

**Release note**:

```
NONE
```
This commit is contained in:
Kubernetes Submit Queue 2017-05-16 09:11:54 -07:00 committed by GitHub
commit ece4124e17
19 changed files with 153 additions and 38 deletions

View File

@ -110,6 +110,8 @@ func NewServerRunOptions() *ServerRunOptions {
} }
// Overwrite the default for storage data format. // Overwrite the default for storage data format.
s.Etcd.DefaultStorageMediaType = "application/vnd.kubernetes.protobuf" s.Etcd.DefaultStorageMediaType = "application/vnd.kubernetes.protobuf"
// Set the default for admission plugins names
s.Admission.PluginNames = []string{"AlwaysAdmit"}
return &s return &s
} }

View File

@ -359,39 +359,41 @@ func BuildGenericConfig(s *options.ServerRunOptions) (*genericapiserver.Config,
genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName) genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName)
} }
genericConfig.AdmissionControl, err = BuildAdmission(s, pluginInitializer, err := BuildAdmissionPluginInitializer(
s.Admission.Plugins, s,
client, client,
sharedInformers, sharedInformers,
genericConfig.Authorizer, genericConfig.Authorizer,
) )
if err != nil { if err != nil {
return nil, nil, nil, fmt.Errorf("failed to initialize admission: %v", err) return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err)
} }
err = s.Admission.ApplyTo(
genericConfig,
pluginInitializer)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to initialize admission: %v", err)
}
return genericConfig, sharedInformers, insecureServingOptions, nil return genericConfig, sharedInformers, insecureServingOptions, nil
} }
// BuildAdmission constructs the admission chain // BuildAdmissionPluginInitializer constructs the admission plugin initializer
func BuildAdmission(s *options.ServerRunOptions, plugins *admission.Plugins, client internalclientset.Interface, sharedInformers informers.SharedInformerFactory, apiAuthorizer authorizer.Authorizer) (admission.Interface, error) { func BuildAdmissionPluginInitializer(s *options.ServerRunOptions, client internalclientset.Interface, sharedInformers informers.SharedInformerFactory, apiAuthorizer authorizer.Authorizer) (admission.PluginInitializer, error) {
admissionControlPluginNames := strings.Split(s.Admission.Control, ",")
var cloudConfig []byte var cloudConfig []byte
var err error
if s.CloudProvider.CloudConfigFile != "" { if s.CloudProvider.CloudConfigFile != "" {
var err error
cloudConfig, err = ioutil.ReadFile(s.CloudProvider.CloudConfigFile) cloudConfig, err = ioutil.ReadFile(s.CloudProvider.CloudConfigFile)
if err != nil { if err != nil {
glog.Fatalf("Error reading from cloud configuration file %s: %#v", s.CloudProvider.CloudConfigFile, err) 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. // TODO: use a dynamic restmapper. See https://github.com/kubernetes/kubernetes/pull/42615.
restMapper := api.Registry.RESTMapper() restMapper := api.Registry.RESTMapper()
pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer, cloudConfig, restMapper) pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer, cloudConfig, restMapper)
admissionConfigProvider, err := admission.ReadAdmissionConfiguration(admissionControlPluginNames, s.Admission.ControlConfigFile) return pluginInitializer, nil
if err != nil {
return nil, fmt.Errorf("failed to read plugin config: %v", err)
}
return plugins.NewFromPlugins(admissionControlPluginNames, admissionConfigProvider, pluginInitializer)
} }
// BuildAuthenticator constructs the authenticator // BuildAuthenticator constructs the authenticator

View File

@ -75,7 +75,6 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_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/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets: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/generic:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest: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:go_default_library",

View File

@ -70,6 +70,8 @@ func NewServerRunOptions() *ServerRunOptions {
} }
// Overwrite the default for storage data format. // Overwrite the default for storage data format.
s.Etcd.DefaultStorageMediaType = "application/vnd.kubernetes.protobuf" s.Etcd.DefaultStorageMediaType = "application/vnd.kubernetes.protobuf"
// Set the default for admission plugins names
s.Admission.PluginNames = []string{"AlwaysAdmit"}
return &s return &s
} }

View File

@ -34,7 +34,6 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/admission"
genericapiserver "k8s.io/apiserver/pkg/server" genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/filters" "k8s.io/apiserver/pkg/server/filters"
serverstorage "k8s.io/apiserver/pkg/server/storage" serverstorage "k8s.io/apiserver/pkg/server/storage"
@ -185,21 +184,20 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
return fmt.Errorf("invalid Authorization Config: %v", err) return fmt.Errorf("invalid Authorization Config: %v", err)
} }
admissionControlPluginNames := strings.Split(s.Admission.Control, ",")
var cloudConfig []byte var cloudConfig []byte
if s.CloudProvider.CloudConfigFile != "" { if s.CloudProvider.CloudConfigFile != "" {
cloudConfig, err = ioutil.ReadFile(s.CloudProvider.CloudConfigFile) cloudConfig, err = ioutil.ReadFile(s.CloudProvider.CloudConfigFile)
if err != nil { if err != nil {
glog.Fatalf("Error reading from cloud configuration file %s: %#v", s.CloudProvider.CloudConfigFile, err) glog.Fatalf("Error reading from cloud configuration file %s: %#v", s.CloudProvider.CloudConfigFile, err)
} }
} }
pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer, cloudConfig, nil) pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, apiAuthorizer, cloudConfig, nil)
admissionConfigProvider, err := admission.ReadAdmissionConfiguration(admissionControlPluginNames, s.Admission.ControlConfigFile)
if err != nil { err = s.Admission.ApplyTo(
return fmt.Errorf("failed to read plugin config: %v", err) genericConfig,
} pluginInitializer,
admissionController, err := kubeapiserveradmission.Plugins.NewFromPlugins(admissionControlPluginNames, admissionConfigProvider, pluginInitializer) )
if err != nil { if err != nil {
return fmt.Errorf("failed to initialize plugins: %v", err) return fmt.Errorf("failed to initialize plugins: %v", err)
} }
@ -208,7 +206,6 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
genericConfig.Version = &kubeVersion genericConfig.Version = &kubeVersion
genericConfig.Authenticator = apiAuthenticator genericConfig.Authenticator = apiAuthenticator
genericConfig.Authorizer = apiAuthorizer genericConfig.Authorizer = apiAuthorizer
genericConfig.AdmissionControl = admissionController
genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapi.GetOpenAPIDefinitions, api.Scheme) genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapi.GetOpenAPIDefinitions, api.Scheme)
genericConfig.OpenAPIConfig.PostProcessSpec = postProcessOpenAPISpecForBackwardCompatibility genericConfig.OpenAPIConfig.PostProcessSpec = postProcessOpenAPISpecForBackwardCompatibility
genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions

View File

@ -142,6 +142,8 @@ go_test(
"//vendor/k8s.io/apiserver/pkg/server/options: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/apiserver/pkg/server/storage:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/etcd/testing: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/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library", "//vendor/k8s.io/client-go/testing:go_default_library",
], ],

View File

@ -37,6 +37,8 @@ import (
"k8s.io/apiserver/pkg/server/options" "k8s.io/apiserver/pkg/server/options"
serverstorage "k8s.io/apiserver/pkg/server/storage" serverstorage "k8s.io/apiserver/pkg/server/storage"
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
@ -101,6 +103,12 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
TLSClientConfig: &tls.Config{}, TLSClientConfig: &tls.Config{},
}) })
clientset, err := kubernetes.NewForConfig(config.GenericConfig.LoopbackClientConfig)
if err != nil {
t.Fatalf("unable to create client set due to %v", err)
}
config.GenericConfig.SharedInformerFactory = informers.NewSharedInformerFactory(clientset, config.GenericConfig.LoopbackClientConfig.Timeout)
return server, *config, assert.New(t) return server, *config, assert.New(t)
} }

View File

@ -36,6 +36,8 @@ go_test(
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library",
"//vendor/k8s.io/client-go/informers:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
], ],
) )
@ -94,6 +96,7 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/mux:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/mux:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/routes:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/routes:go_default_library",
"//vendor/k8s.io/client-go/informers:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/util/cert:go_default_library", "//vendor/k8s.io/client-go/util/cert:go_default_library",
], ],

View File

@ -54,6 +54,7 @@ import (
genericfilters "k8s.io/apiserver/pkg/server/filters" genericfilters "k8s.io/apiserver/pkg/server/filters"
"k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/healthz"
"k8s.io/apiserver/pkg/server/routes" "k8s.io/apiserver/pkg/server/routes"
"k8s.io/client-go/informers"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
@ -109,6 +110,8 @@ type Config struct {
// Will default to a value based on secure serving info and available ipv4 IPs. // Will default to a value based on secure serving info and available ipv4 IPs.
ExternalAddress string ExternalAddress string
// SharedInformerFactory provides shared informers for resources
SharedInformerFactory informers.SharedInformerFactory
//=========================================================================== //===========================================================================
// Fields you probably don't care about changing // Fields you probably don't care about changing
//=========================================================================== //===========================================================================
@ -405,6 +408,16 @@ func (c completedConfig) New(delegationTarget DelegationTarget) (*GenericAPIServ
s.postStartHooks[k] = v s.postStartHooks[k] = v
} }
genericApiServerHookName := "generic-apiserver-start-informers"
if c.SharedInformerFactory != nil && !s.isHookRegistered(genericApiServerHookName) {
err := s.AddPostStartHook(genericApiServerHookName, func(context PostStartHookContext) error {
c.SharedInformerFactory.Start(context.StopCh)
return nil
})
if err != nil {
return nil, err
}
}
for _, delegateCheck := range delegationTarget.HealthzChecks() { for _, delegateCheck := range delegationTarget.HealthzChecks() {
skip := false skip := false
for _, existingCheck := range c.HealthzChecks { for _, existingCheck := range c.HealthzChecks {

View File

@ -28,6 +28,8 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/healthz"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
) )
@ -38,6 +40,11 @@ func TestNewWithDelegate(t *testing.T) {
delegateConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") delegateConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
delegateConfig.LoopbackClientConfig = &rest.Config{} delegateConfig.LoopbackClientConfig = &rest.Config{}
delegateConfig.SwaggerConfig = DefaultSwaggerConfig() delegateConfig.SwaggerConfig = DefaultSwaggerConfig()
clientset := fake.NewSimpleClientset()
if clientset == nil {
t.Fatal("unable to create fake client set")
}
delegateConfig.SharedInformerFactory = informers.NewSharedInformerFactory(clientset, delegateConfig.LoopbackClientConfig.Timeout)
delegateHealthzCalled := false delegateHealthzCalled := false
delegateConfig.HealthzChecks = append(delegateConfig.HealthzChecks, healthz.NamedCheck("delegate-health", func(r *http.Request) error { delegateConfig.HealthzChecks = append(delegateConfig.HealthzChecks, healthz.NamedCheck("delegate-health", func(r *http.Request) error {
@ -66,6 +73,7 @@ func TestNewWithDelegate(t *testing.T) {
wrappingConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") wrappingConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
wrappingConfig.LoopbackClientConfig = &rest.Config{} wrappingConfig.LoopbackClientConfig = &rest.Config{}
wrappingConfig.SwaggerConfig = DefaultSwaggerConfig() wrappingConfig.SwaggerConfig = DefaultSwaggerConfig()
wrappingConfig.SharedInformerFactory = informers.NewSharedInformerFactory(clientset, wrappingConfig.LoopbackClientConfig.Timeout)
wrappingHealthzCalled := false wrappingHealthzCalled := false
wrappingConfig.HealthzChecks = append(wrappingConfig.HealthzChecks, healthz.NamedCheck("wrapping-health", func(r *http.Request) error { wrappingConfig.HealthzChecks = append(wrappingConfig.HealthzChecks, healthz.NamedCheck("wrapping-health", func(r *http.Request) error {
@ -102,6 +110,7 @@ func TestNewWithDelegate(t *testing.T) {
"/healthz/delegate-health", "/healthz/delegate-health",
"/healthz/ping", "/healthz/ping",
"/healthz/poststarthook/delegate-post-start-hook", "/healthz/poststarthook/delegate-post-start-hook",
"/healthz/poststarthook/generic-apiserver-start-informers",
"/healthz/poststarthook/wrapping-post-start-hook", "/healthz/poststarthook/wrapping-post-start-hook",
"/healthz/wrapping-health", "/healthz/wrapping-health",
"/swaggerapi/" "/swaggerapi/"
@ -110,6 +119,7 @@ func TestNewWithDelegate(t *testing.T) {
checkPath(server.URL+"/healthz", http.StatusInternalServerError, `[+]ping ok checkPath(server.URL+"/healthz", http.StatusInternalServerError, `[+]ping ok
[-]wrapping-health failed: reason withheld [-]wrapping-health failed: reason withheld
[-]delegate-health failed: reason withheld [-]delegate-health failed: reason withheld
[+]poststarthook/generic-apiserver-start-informers ok
[+]poststarthook/delegate-post-start-hook ok [+]poststarthook/delegate-post-start-hook ok
[+]poststarthook/wrapping-post-start-hook ok [+]poststarthook/wrapping-post-start-hook ok
healthz check failed healthz check failed

View File

@ -48,6 +48,8 @@ import (
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
) )
@ -90,6 +92,12 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
config.LegacyAPIGroupPrefixes = sets.NewString("/api") config.LegacyAPIGroupPrefixes = sets.NewString("/api")
config.LoopbackClientConfig = &restclient.Config{} config.LoopbackClientConfig = &restclient.Config{}
clientset := fake.NewSimpleClientset()
if clientset == nil {
t.Fatal("unable to create fake client set")
}
config.SharedInformerFactory = informers.NewSharedInformerFactory(clientset, config.LoopbackClientConfig.Timeout)
// TODO restore this test, but right now, eliminate our cycle // TODO restore this test, but right now, eliminate our cycle
// config.OpenAPIConfig = DefaultOpenAPIConfig(testGetOpenAPIDefinitions, runtime.NewScheme()) // config.OpenAPIConfig = DefaultOpenAPIConfig(testGetOpenAPIDefinitions, runtime.NewScheme())
// config.OpenAPIConfig.Info = &spec.Info{ // config.OpenAPIConfig.Info = &spec.Info{
@ -300,17 +308,13 @@ func TestPrepareRun(t *testing.T) {
defer etcdserver.Terminate(t) defer etcdserver.Terminate(t)
assert.NotNil(config.SwaggerConfig) assert.NotNil(config.SwaggerConfig)
// assert.NotNil(config.OpenAPIConfig)
server := httptest.NewServer(s.Handler.GoRestfulContainer.ServeMux) server := httptest.NewServer(s.Handler.GoRestfulContainer.ServeMux)
defer server.Close() defer server.Close()
done := make(chan struct{})
s.PrepareRun() s.PrepareRun()
s.RunPostStartHooks(done)
// openapi is installed in PrepareRun
// resp, err := http.Get(server.URL + "/swagger.json")
// assert.NoError(err)
// assert.Equal(http.StatusOK, resp.StatusCode)
// swagger is installed in PrepareRun // swagger is installed in PrepareRun
resp, err := http.Get(server.URL + "/swaggerapi/") resp, err := http.Get(server.URL + "/swaggerapi/")

View File

@ -106,6 +106,14 @@ func (s *GenericAPIServer) RunPostStartHooks(stopCh <-chan struct{}) {
} }
} }
// isHookRegistered checks whether a given hook is registered
func (s *GenericAPIServer) isHookRegistered(name string) bool {
s.postStartHookLock.Lock()
defer s.postStartHookLock.Unlock()
_, exists := s.postStartHooks[name]
return exists
}
func runPostStartHook(name string, entry postStartHookEntry, context PostStartHookContext) { func runPostStartHook(name string, entry postStartHookEntry, context PostStartHookContext) {
var err error var err error
func() { func() {
@ -117,7 +125,6 @@ func runPostStartHook(name string, entry postStartHookEntry, context PostStartHo
if err != nil { if err != nil {
glog.Fatalf("PostStartHook %q failed: %v", name, err) glog.Fatalf("PostStartHook %q failed: %v", name, err)
} }
close(entry.done) close(entry.done)
} }

View File

@ -53,6 +53,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/net: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: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/authentication/authenticatorfactory:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory: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/features:go_default_library",
@ -63,6 +64,8 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_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/feature:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag: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/authentication/v1beta1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/authorization/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", "//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",

View File

@ -17,33 +17,70 @@ limitations under the License.
package options package options
import ( import (
"fmt"
"strings" "strings"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/apiserver/pkg/server"
"k8s.io/client-go/kubernetes"
) )
// AdmissionOptions holds the admission options // AdmissionOptions holds the admission options
type AdmissionOptions struct { type AdmissionOptions struct {
Control string PluginNames []string
ControlConfigFile string ConfigFile string
Plugins *admission.Plugins Plugins *admission.Plugins
} }
// NewAdmissionOptions creates a new instance of AdmissionOptions // NewAdmissionOptions creates a new instance of AdmissionOptions
func NewAdmissionOptions(plugins *admission.Plugins) *AdmissionOptions { func NewAdmissionOptions(plugins *admission.Plugins) *AdmissionOptions {
return &AdmissionOptions{ return &AdmissionOptions{
Plugins: plugins, Plugins: plugins,
Control: "AlwaysAdmit", PluginNames: []string{},
} }
} }
// AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet // AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet
func (a *AdmissionOptions) AddFlags(fs *pflag.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. "+ "Ordered list of plug-ins to do admission control of resources into cluster. "+
"Comma-delimited list of: "+strings.Join(a.Plugins.Registered(), ", ")+".") "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.") "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
// note this method uses:
// genericconfig.LoopbackClientConfig
// genericconfig.SharedInformerFactory
// genericconfig.Authorizer
func (a *AdmissionOptions) ApplyTo(serverCfg *server.Config, 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)
}
clientset, err := kubernetes.NewForConfig(serverCfg.LoopbackClientConfig)
if err != nil {
return err
}
genericInitializer, err := initializer.New(clientset, serverCfg.SharedInformerFactory, serverCfg.Authorizer)
if err != nil {
return err
}
initializersChain := admission.PluginInitializers{}
pluginInitializers = append(pluginInitializers, genericInitializer)
initializersChain = append(initializersChain, pluginInitializers...)
admissionChain, err := a.Plugins.NewFromPlugins(a.PluginNames, pluginsConfigProvider, initializersChain)
if err != nil {
return err
}
serverCfg.AdmissionControl = admissionChain
return nil
}

View File

@ -32,6 +32,8 @@ import (
utilnet "k8s.io/apimachinery/pkg/util/net" utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server"
utilflag "k8s.io/apiserver/pkg/util/flag" utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
) )
@ -167,6 +169,13 @@ func (s *SecureServingOptions) ApplyTo(c *server.Config) error {
c.SecureServingInfo.SNICerts[server.LoopbackClientServerNameOverride] = &tlsCert c.SecureServingInfo.SNICerts[server.LoopbackClientServerNameOverride] = &tlsCert
} }
// create shared informers
clientset, err := kubernetes.NewForConfig(c.LoopbackClientConfig)
if err != nil {
return err
}
c.SharedInformerFactory = informers.NewSharedInformerFactory(clientset, c.LoopbackClientConfig.Timeout)
return nil return nil
} }

View File

@ -114,6 +114,10 @@
"ImportPath": "github.com/ghodss/yaml", "ImportPath": "github.com/ghodss/yaml",
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee" "Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
}, },
{
"ImportPath": "github.com/go-openapi/analysis",
"Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b"
},
{ {
"ImportPath": "github.com/go-openapi/jsonpointer", "ImportPath": "github.com/go-openapi/jsonpointer",
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98" "Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
@ -122,6 +126,10 @@
"ImportPath": "github.com/go-openapi/jsonreference", "ImportPath": "github.com/go-openapi/jsonreference",
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272" "Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
}, },
{
"ImportPath": "github.com/go-openapi/loads",
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
},
{ {
"ImportPath": "github.com/go-openapi/spec", "ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff" "Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"

View File

@ -104,7 +104,6 @@ func startServer(t *testing.T, runOptions *options.ServerRunOptions, stopChan <-
} }
runOptions.InsecureServing.BindPort = port runOptions.InsecureServing.BindPort = port
err = app.NonBlockingRun(runOptions, stopChan) err = app.NonBlockingRun(runOptions, stopChan)
if err != nil { if err != nil {
t.Logf("Error starting the %s: %v", apiNoun, err) t.Logf("Error starting the %s: %v", apiNoun, err)

View File

@ -63,6 +63,8 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/server/options: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/apiserver/pkg/server/storage:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/storagebackend: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/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library", "//vendor/k8s.io/client-go/tools/record:go_default_library",
], ],

View File

@ -47,6 +47,8 @@ import (
"k8s.io/apiserver/pkg/server/options" "k8s.io/apiserver/pkg/server/options"
serverstorage "k8s.io/apiserver/pkg/server/storage" serverstorage "k8s.io/apiserver/pkg/server/storage"
"k8s.io/apiserver/pkg/storage/storagebackend" "k8s.io/apiserver/pkg/storage/storagebackend"
extinformers "k8s.io/client-go/informers"
extclient "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
@ -245,7 +247,13 @@ func startMasterOrDie(masterConfig *master.Config, incomingServer *httptest.Serv
masterConfig.GenericConfig.LoopbackClientConfig.BearerToken = privilegedLoopbackToken masterConfig.GenericConfig.LoopbackClientConfig.BearerToken = privilegedLoopbackToken
m, err := masterConfig.Complete().New(genericapiserver.EmptyDelegate) clientset, err := extclient.NewForConfig(masterConfig.GenericConfig.LoopbackClientConfig)
if err != nil {
glog.Fatal(err)
}
masterConfig.GenericConfig.SharedInformerFactory = extinformers.NewSharedInformerFactory(clientset, masterConfig.GenericConfig.LoopbackClientConfig.Timeout)
m, err = masterConfig.Complete().New(genericapiserver.EmptyDelegate)
if err != nil { if err != nil {
closeFn() closeFn()
glog.Fatalf("error in bringing up the master: %v", err) glog.Fatalf("error in bringing up the master: %v", err)