mirror of https://github.com/k3s-io/k3s
make admission config scheme configurable
parent
4dd136050f
commit
ccd4f4a4b6
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,6 +45,7 @@ type AdmissionOptions struct {
|
|||
DefaultOffPlugins []string
|
||||
PluginNames []string
|
||||
ConfigFile string
|
||||
|
||||
Plugins *admission.Plugins
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue