diff --git a/plugin/pkg/admission/resourcequota/admission.go b/plugin/pkg/admission/resourcequota/admission.go index c6e89aad806..24f8b6354b9 100644 --- a/plugin/pkg/admission/resourcequota/admission.go +++ b/plugin/pkg/admission/resourcequota/admission.go @@ -28,6 +28,7 @@ import ( kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/quota" resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota" + resourcequotaapiv1alpha1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1" "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation" ) @@ -48,6 +49,10 @@ func Register(plugins *admission.Plugins) { } return NewResourceQuota(configuration, 5, make(chan struct{})) }) + + // add our config types + resourcequotaapi.AddToScheme(plugins.ConfigScheme) + resourcequotaapiv1alpha1.AddToScheme(plugins.ConfigScheme) } // QuotaAdmission implements an admission controller that can enforce quota constraints diff --git a/staging/src/k8s.io/apiserver/pkg/admission/BUILD b/staging/src/k8s.io/apiserver/pkg/admission/BUILD index 89737671a89..65542c02016 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/admission/BUILD @@ -21,6 +21,7 @@ go_test( "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/apiserver:go_default_library", + "//vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1:go_default_library", ], ) @@ -41,15 +42,12 @@ go_library( "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/serializer: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/apis/apiserver:go_default_library", - "//vendor/k8s.io/apiserver/pkg/apis/apiserver/install:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library", ], diff --git a/staging/src/k8s.io/apiserver/pkg/admission/config.go b/staging/src/k8s.io/apiserver/pkg/admission/config.go index d233c7cb92b..72da98fe263 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/config.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/config.go @@ -29,27 +29,14 @@ import ( "bytes" - "k8s.io/apimachinery/pkg/apimachinery/announced" - "k8s.io/apimachinery/pkg/apimachinery/registered" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/apis/apiserver" - "k8s.io/apiserver/pkg/apis/apiserver/install" apiserverv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" ) -var ( - groupFactoryRegistry = make(announced.APIGroupFactoryRegistry) - registry = registered.NewOrDie(os.Getenv("KUBE_API_VERSIONS")) - scheme = runtime.NewScheme() - codecs = serializer.NewCodecFactory(scheme) -) - -func init() { - install.Install(groupFactoryRegistry, registry, scheme) -} - func makeAbs(path, base string) (string, error) { if filepath.IsAbs(path) { return path, nil @@ -70,7 +57,7 @@ func makeAbs(path, base string) (string, error) { // set of pluginNames whose config location references the specified configFilePath. // It does this to preserve backward compatibility when admission control files were opaque. // It returns an error if the file did not exist. -func ReadAdmissionConfiguration(pluginNames []string, configFilePath string) (ConfigProvider, error) { +func ReadAdmissionConfiguration(pluginNames []string, configFilePath string, configScheme *runtime.Scheme) (ConfigProvider, error) { if configFilePath == "" { return configProvider{config: &apiserver.AdmissionConfiguration{}}, nil } @@ -79,6 +66,7 @@ func ReadAdmissionConfiguration(pluginNames []string, configFilePath string) (Co if err != nil { return nil, fmt.Errorf("unable to read admission control configuration from %q [%v]", configFilePath, err) } + codecs := serializer.NewCodecFactory(configScheme) decoder := codecs.UniversalDecoder() decodedObj, err := runtime.Decode(decoder, data) // we were able to decode the file successfully @@ -99,7 +87,10 @@ func ReadAdmissionConfiguration(pluginNames []string, configFilePath string) (Co } decodedConfig.Plugins[i].Path = absPath } - return configProvider{config: decodedConfig}, nil + return configProvider{ + config: decodedConfig, + scheme: configScheme, + }, nil } // we got an error where the decode wasn't related to a missing type if !(runtime.IsMissingVersion(err) || runtime.IsMissingKind(err) || runtime.IsNotRegisteredError(err)) { @@ -119,25 +110,29 @@ func ReadAdmissionConfiguration(pluginNames []string, configFilePath string) (Co Path: configFilePath}) } } - scheme.Default(externalConfig) + configScheme.Default(externalConfig) internalConfig := &apiserver.AdmissionConfiguration{} - if err := scheme.Convert(externalConfig, internalConfig, nil); err != nil { + if err := configScheme.Convert(externalConfig, internalConfig, nil); err != nil { return nil, err } - return configProvider{config: internalConfig}, nil + return configProvider{ + config: internalConfig, + scheme: configScheme, + }, nil } type configProvider struct { config *apiserver.AdmissionConfiguration + scheme *runtime.Scheme } // GetAdmissionPluginConfigurationFor returns a reader that holds the admission plugin configuration. -func GetAdmissionPluginConfigurationFor(pluginCfg apiserver.AdmissionPluginConfiguration) (io.Reader, error) { +func GetAdmissionPluginConfigurationFor(pluginCfg apiserver.AdmissionPluginConfiguration, scheme *runtime.Scheme) (io.Reader, error) { // if there is nothing nested in the object, we return the named location obj := pluginCfg.Configuration if obj != nil { // serialize the configuration and build a reader for it - content, err := writeYAML(obj) + content, err := writeYAML(obj, scheme) if err != nil { return nil, err } @@ -168,7 +163,7 @@ func (p configProvider) ConfigFor(pluginName string) (io.Reader, error) { if pluginName != pluginCfg.Name { continue } - pluginConfig, err := GetAdmissionPluginConfigurationFor(pluginCfg) + pluginConfig, err := GetAdmissionPluginConfigurationFor(pluginCfg, p.scheme) if err != nil { return nil, err } @@ -179,8 +174,17 @@ func (p configProvider) ConfigFor(pluginName string) (io.Reader, error) { } // writeYAML writes the specified object to a byte array as yaml. -func writeYAML(obj runtime.Object) ([]byte, error) { - json, err := runtime.Encode(codecs.LegacyCodec(), obj) +func writeYAML(obj runtime.Object, scheme *runtime.Scheme) ([]byte, error) { + gvks, _, err := scheme.ObjectKinds(obj) + if err != nil { + return nil, err + } + gvs := []schema.GroupVersion{} + for _, gvk := range gvks { + gvs = append(gvs, gvk.GroupVersion()) + } + codecs := serializer.NewCodecFactory(scheme) + json, err := runtime.Encode(codecs.LegacyCodec(gvs...), obj) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/config_test.go b/staging/src/k8s.io/apiserver/pkg/admission/config_test.go index 13489bed287..debde2463d2 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/config_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/config_test.go @@ -22,7 +22,10 @@ import ( "reflect" "testing" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/apis/apiserver" + apiserverapi "k8s.io/apiserver/pkg/apis/apiserver" + apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" ) func TestReadAdmissionConfiguration(t *testing.T) { @@ -132,11 +135,16 @@ func TestReadAdmissionConfiguration(t *testing.T) { PluginNames: []string{"NamespaceLifecycle", "InitialResources"}, }, } + + scheme := runtime.NewScheme() + apiserverapi.AddToScheme(scheme) + apiserverapiv1alpha1.AddToScheme(scheme) + for testName, testCase := range testCases { if err = ioutil.WriteFile(configFileName, []byte(testCase.ConfigBody), 0644); err != nil { t.Fatalf("unexpected err writing temp file: %v", err) } - config, err := ReadAdmissionConfiguration(testCase.PluginNames, configFileName) + config, err := ReadAdmissionConfiguration(testCase.PluginNames, configFileName, scheme) if err != nil { t.Fatalf("unexpected err: %v", err) } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/BUILD b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/BUILD index 08f2ef795f6..8a0e21b8541 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/BUILD @@ -13,14 +13,12 @@ go_library( deps = [ "//vendor/github.com/hashicorp/golang-lru:go_default_library", "//vendor/k8s.io/api/admissionregistration/v1alpha1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission:go_default_library", + "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors:go_default_library", - "//vendor/k8s.io/apiserver/pkg/apis/audit/install:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/tools/clientcmd:go_default_library", "//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/BUILD b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/BUILD index cf2890efd4d..141a3e589ac 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/BUILD @@ -23,6 +23,8 @@ go_library( "//vendor/k8s.io/apiserver/pkg/admission/initializer:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/metrics:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config:go_default_library", + "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission:go_default_library", + "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/request:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/admission.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/admission.go index d3d24d17fb7..0adef777825 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/admission.go @@ -40,6 +40,8 @@ import ( genericadmissioninit "k8s.io/apiserver/pkg/admission/initializer" admissionmetrics "k8s.io/apiserver/pkg/admission/metrics" "k8s.io/apiserver/pkg/admission/plugin/webhook/config" + webhookadmissionapi "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission" + webhookadmissionapiv1alpha1 "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1alpha1" webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors" "k8s.io/apiserver/pkg/admission/plugin/webhook/namespace" "k8s.io/apiserver/pkg/admission/plugin/webhook/request" @@ -64,6 +66,9 @@ func Register(plugins *admission.Plugins) { return plugin, nil }) + // add our config types + webhookadmissionapi.AddToScheme(plugins.ConfigScheme) + webhookadmissionapiv1alpha1.AddToScheme(plugins.ConfigScheme) } // WebhookSource can list dynamic webhook plugins. diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugins.go b/staging/src/k8s.io/apiserver/pkg/admission/plugins.go index 3639df3da6d..3ede44a173f 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugins.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugins.go @@ -25,6 +25,8 @@ import ( "sort" "sync" + "k8s.io/apimachinery/pkg/runtime" + "github.com/golang/glog" ) @@ -37,6 +39,16 @@ type Factory func(config io.Reader) (Interface, error) type Plugins struct { lock sync.Mutex registry map[string]Factory + + // ConfigScheme is used to parse the admission plugin config file. + // It is exposed to act as a hook for extending server providing their own config. + ConfigScheme *runtime.Scheme +} + +func NewPlugins() *Plugins { + return &Plugins{ + ConfigScheme: runtime.NewScheme(), + } } // All registered admission options. diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/BUILD b/staging/src/k8s.io/apiserver/pkg/server/options/BUILD index 3fc9df50f20..7a9196f14d6 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/server/options/BUILD @@ -35,6 +35,8 @@ go_library( "//vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating:go_default_library", + "//vendor/k8s.io/apiserver/pkg/apis/apiserver:go_default_library", + "//vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit/policy: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 393805225e0..a0b1aa983a0 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go @@ -29,6 +29,8 @@ import ( "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" @@ -43,7 +45,8 @@ type AdmissionOptions struct { DefaultOffPlugins []string PluginNames []string ConfigFile string - Plugins *admission.Plugins + + Plugins *admission.Plugins } // NewAdmissionOptions creates a new instance of AdmissionOptions @@ -56,11 +59,13 @@ type AdmissionOptions struct { // Servers that do care can overwrite/append that field after creation. func NewAdmissionOptions() *AdmissionOptions { options := &AdmissionOptions{ - Plugins: &admission.Plugins{}, + Plugins: admission.NewPlugins(), PluginNames: []string{}, RecommendedPluginOrder: []string{mutatingwebhook.PluginName, lifecycle.PluginName, initialization.PluginName, validatingwebhook.PluginName}, DefaultOffPlugins: []string{mutatingwebhook.PluginName, initialization.PluginName, validatingwebhook.PluginName}, } + apiserverapi.AddToScheme(options.Plugins.ConfigScheme) + apiserverapiv1alpha1.AddToScheme(options.Plugins.ConfigScheme) server.RegisterAllAdmissionPlugins(options.Plugins) return options } @@ -96,7 +101,7 @@ func (a *AdmissionOptions) ApplyTo( pluginNames = a.enabledPluginNames() } - pluginsConfigProvider, err := admission.ReadAdmissionConfiguration(pluginNames, a.ConfigFile) + pluginsConfigProvider, err := admission.ReadAdmissionConfiguration(pluginNames, a.ConfigFile, a.Plugins.ConfigScheme) if err != nil { return fmt.Errorf("failed to read plugin config: %v", err) }