Skip to content

Commit 6abdfb9

Browse files
authored
Merge pull request kubernetes#124621 from sttts/sttts-controlplane-admission-initializers
kube-apiserver: split admission initializers into generic and non-generic
2 parents b276088 + acbb89d commit 6abdfb9

File tree

9 files changed

+215
-106
lines changed

9 files changed

+215
-106
lines changed

cmd/kube-apiserver/app/server.go

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import (
5757
"k8s.io/klog/v2"
5858
aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver"
5959
aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
60+
controlplaneadmission "k8s.io/kubernetes/pkg/controlplane/apiserver/admission"
6061

6162
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
6263
"k8s.io/kubernetes/pkg/api/legacyscheme"
@@ -223,8 +224,29 @@ func CreateKubeAPIServerConfig(opts options.CompletedOptions) (
223224
generatedopenapi.GetOpenAPIDefinitions,
224225
)
225226
if err != nil {
226-
return nil, nil, nil, err
227+
return nil, nil, nil, fmt.Errorf("failed to create generic config: %w", err)
228+
}
229+
230+
// generic controlplane admission initializers
231+
controlPlaneAdmissionConfig := &controlplaneadmission.Config{
232+
ExternalInformers: versionedInformers,
233+
LoopbackClientConfig: genericConfig.LoopbackClientConfig,
234+
}
235+
serviceResolver := buildServiceResolver(opts.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers)
236+
pluginInitializers, err := controlPlaneAdmissionConfig.New(proxyTransport, genericConfig.EgressSelector, serviceResolver, genericConfig.TracerProvider)
237+
if err != nil {
238+
return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %w", err)
239+
}
240+
241+
// additional kube admission initializers
242+
kubeAdmissionConfig := &kubeapiserveradmission.Config{
243+
CloudConfigFile: opts.CloudProvider.CloudConfigFile,
244+
}
245+
kubeInitializers, err := kubeAdmissionConfig.New()
246+
if err != nil {
247+
return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %w", err)
227248
}
249+
pluginInitializers = append(pluginInitializers, kubeInitializers...)
228250

229251
capabilities.Setup(opts.AllowPrivileged, opts.MaxConnectionBytesPerSec)
230252

@@ -300,16 +322,6 @@ func CreateKubeAPIServerConfig(opts options.CompletedOptions) (
300322
}
301323

302324
// setup admission
303-
admissionConfig := &kubeapiserveradmission.Config{
304-
ExternalInformers: versionedInformers,
305-
LoopbackClientConfig: genericConfig.LoopbackClientConfig,
306-
CloudConfigFile: opts.CloudProvider.CloudConfigFile,
307-
}
308-
serviceResolver := buildServiceResolver(opts.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers)
309-
pluginInitializers, err := admissionConfig.New(proxyTransport, genericConfig.EgressSelector, serviceResolver, genericConfig.TracerProvider)
310-
if err != nil {
311-
return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err)
312-
}
313325
clientgoExternalClient, err := clientset.NewForConfig(genericConfig.LoopbackClientConfig)
314326
if err != nil {
315327
return nil, nil, nil, fmt.Errorf("failed to create real client-go external client: %w", err)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package admission
18+
19+
import (
20+
"net/http"
21+
22+
"go.opentelemetry.io/otel/trace"
23+
24+
"k8s.io/apiserver/pkg/admission"
25+
webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer"
26+
egressselector "k8s.io/apiserver/pkg/server/egressselector"
27+
"k8s.io/apiserver/pkg/util/webhook"
28+
externalinformers "k8s.io/client-go/informers"
29+
"k8s.io/client-go/rest"
30+
"k8s.io/kubernetes/pkg/kubeapiserver/admission/exclusion"
31+
quotainstall "k8s.io/kubernetes/pkg/quota/v1/install"
32+
)
33+
34+
// Config holds the configuration needed to for initialize the admission plugins
35+
type Config struct {
36+
LoopbackClientConfig *rest.Config
37+
ExternalInformers externalinformers.SharedInformerFactory
38+
}
39+
40+
// New sets up the plugins and admission start hooks needed for admission
41+
func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider) ([]admission.PluginInitializer, error) {
42+
webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig, tp)
43+
webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver)
44+
45+
kubePluginInitializer := NewPluginInitializer(
46+
quotainstall.NewQuotaConfigurationForAdmission(),
47+
exclusion.Excluded(),
48+
)
49+
50+
return []admission.PluginInitializer{webhookPluginInitializer, kubePluginInitializer}, nil
51+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package admission
18+
19+
import (
20+
"k8s.io/apimachinery/pkg/runtime/schema"
21+
"k8s.io/apiserver/pkg/admission"
22+
"k8s.io/apiserver/pkg/admission/initializer"
23+
quota "k8s.io/apiserver/pkg/quota/v1"
24+
)
25+
26+
// PluginInitializer is used for initialization of the generic controlplane admission plugins.
27+
type PluginInitializer struct {
28+
quotaConfiguration quota.Configuration
29+
excludedAdmissionResources []schema.GroupResource
30+
}
31+
32+
var _ admission.PluginInitializer = &PluginInitializer{}
33+
34+
// NewPluginInitializer constructs new instance of PluginInitializer
35+
func NewPluginInitializer(
36+
quotaConfiguration quota.Configuration,
37+
excludedAdmissionResources []schema.GroupResource,
38+
) *PluginInitializer {
39+
return &PluginInitializer{
40+
quotaConfiguration: quotaConfiguration,
41+
excludedAdmissionResources: excludedAdmissionResources,
42+
}
43+
}
44+
45+
// Initialize checks the initialization interfaces implemented by each plugin
46+
// and provide the appropriate initialization data
47+
func (i *PluginInitializer) Initialize(plugin admission.Interface) {
48+
if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok {
49+
wants.SetQuotaConfiguration(i.quotaConfiguration)
50+
}
51+
52+
if wants, ok := plugin.(initializer.WantsExcludedAdmissionResources); ok {
53+
wants.SetExcludedAdmissionResources(i.excludedAdmissionResources)
54+
}
55+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package admission
18+
19+
import (
20+
"context"
21+
"testing"
22+
23+
"k8s.io/apimachinery/pkg/runtime/schema"
24+
"k8s.io/apiserver/pkg/admission"
25+
quota "k8s.io/apiserver/pkg/quota/v1"
26+
)
27+
28+
type doNothingAdmission struct{}
29+
30+
func (doNothingAdmission) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
31+
return nil
32+
}
33+
func (doNothingAdmission) Handles(o admission.Operation) bool { return false }
34+
func (doNothingAdmission) Validate() error { return nil }
35+
36+
type doNothingPluginInitialization struct{}
37+
38+
func (doNothingPluginInitialization) ValidateInitialization() error { return nil }
39+
40+
type doNothingQuotaConfiguration struct{}
41+
42+
func (doNothingQuotaConfiguration) IgnoredResources() map[schema.GroupResource]struct{} { return nil }
43+
44+
func (doNothingQuotaConfiguration) Evaluators() []quota.Evaluator { return nil }
45+
46+
type WantsQuotaConfigurationAdmissionPlugin struct {
47+
doNothingAdmission
48+
doNothingPluginInitialization
49+
config quota.Configuration
50+
}
51+
52+
func (p *WantsQuotaConfigurationAdmissionPlugin) SetQuotaConfiguration(config quota.Configuration) {
53+
p.config = config
54+
}
55+
56+
func TestQuotaConfigurationAdmissionPlugin(t *testing.T) {
57+
config := doNothingQuotaConfiguration{}
58+
initializer := NewPluginInitializer(config, nil)
59+
wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{}
60+
initializer.Initialize(wantsQuotaConfigurationAdmission)
61+
62+
if wantsQuotaConfigurationAdmission.config == nil {
63+
t.Errorf("Expected quota configuration to be initialized but found nil")
64+
}
65+
}

pkg/kubeapiserver/admission/config.go

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,20 @@ limitations under the License.
1717
package admission
1818

1919
import (
20-
"net/http"
2120
"os"
2221

2322
"k8s.io/klog/v2"
2423

25-
"go.opentelemetry.io/otel/trace"
26-
2724
"k8s.io/apiserver/pkg/admission"
28-
webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer"
29-
"k8s.io/apiserver/pkg/server/egressselector"
30-
"k8s.io/apiserver/pkg/util/webhook"
31-
externalinformers "k8s.io/client-go/informers"
32-
"k8s.io/client-go/rest"
33-
"k8s.io/kubernetes/pkg/kubeapiserver/admission/exclusion"
34-
quotainstall "k8s.io/kubernetes/pkg/quota/v1/install"
3525
)
3626

3727
// Config holds the configuration needed to for initialize the admission plugins
3828
type Config struct {
39-
CloudConfigFile string
40-
LoopbackClientConfig *rest.Config
41-
ExternalInformers externalinformers.SharedInformerFactory
29+
CloudConfigFile string
4230
}
4331

4432
// New sets up the plugins and admission start hooks needed for admission
45-
func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider) ([]admission.PluginInitializer, error) {
46-
webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig, tp)
47-
webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver)
48-
33+
func (c *Config) New() ([]admission.PluginInitializer, error) {
4934
var cloudConfig []byte
5035
if c.CloudConfigFile != "" {
5136
var err error
@@ -54,11 +39,6 @@ func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselec
5439
klog.Fatalf("Error reading from cloud configuration file %s: %#v", c.CloudConfigFile, err)
5540
}
5641
}
57-
kubePluginInitializer := NewPluginInitializer(
58-
cloudConfig,
59-
quotainstall.NewQuotaConfigurationForAdmission(),
60-
exclusion.Excluded(),
61-
)
6242

63-
return []admission.PluginInitializer{webhookPluginInitializer, kubePluginInitializer}, nil
43+
return []admission.PluginInitializer{NewPluginInitializer(cloudConfig)}, nil
6444
}

pkg/kubeapiserver/admission/initializer.go

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ limitations under the License.
1717
package admission
1818

1919
import (
20-
"k8s.io/apimachinery/pkg/runtime/schema"
2120
"k8s.io/apiserver/pkg/admission"
22-
"k8s.io/apiserver/pkg/admission/initializer"
23-
quota "k8s.io/apiserver/pkg/quota/v1"
2421
)
2522

2623
// TODO add a `WantsToRun` which takes a stopCh. Might make it generic.
@@ -32,25 +29,15 @@ type WantsCloudConfig interface {
3229

3330
// PluginInitializer is used for initialization of the Kubernetes specific admission plugins.
3431
type PluginInitializer struct {
35-
cloudConfig []byte
36-
quotaConfiguration quota.Configuration
37-
excludedAdmissionResources []schema.GroupResource
32+
cloudConfig []byte
3833
}
3934

4035
var _ admission.PluginInitializer = &PluginInitializer{}
4136

4237
// NewPluginInitializer constructs new instance of PluginInitializer
43-
// TODO: switch these parameters to use the builder pattern or just make them
44-
// all public, this construction method is pointless boilerplate.
45-
func NewPluginInitializer(
46-
cloudConfig []byte,
47-
quotaConfiguration quota.Configuration,
48-
excludedAdmissionResources []schema.GroupResource,
49-
) *PluginInitializer {
38+
func NewPluginInitializer(cloudConfig []byte) *PluginInitializer {
5039
return &PluginInitializer{
51-
cloudConfig: cloudConfig,
52-
quotaConfiguration: quotaConfiguration,
53-
excludedAdmissionResources: excludedAdmissionResources,
40+
cloudConfig: cloudConfig,
5441
}
5542
}
5643

@@ -60,12 +47,4 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) {
6047
if wants, ok := plugin.(WantsCloudConfig); ok {
6148
wants.SetCloudConfig(i.cloudConfig)
6249
}
63-
64-
if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok {
65-
wants.SetQuotaConfiguration(i.quotaConfiguration)
66-
}
67-
68-
if wants, ok := plugin.(initializer.WantsExcludedAdmissionResources); ok {
69-
wants.SetExcludedAdmissionResources(i.excludedAdmissionResources)
70-
}
7150
}

pkg/kubeapiserver/admission/initializer_test.go

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ import (
2020
"context"
2121
"testing"
2222

23-
"k8s.io/apimachinery/pkg/runtime/schema"
2423
"k8s.io/apiserver/pkg/admission"
25-
quota "k8s.io/apiserver/pkg/quota/v1"
2624
)
2725

2826
type doNothingAdmission struct{}
@@ -33,10 +31,6 @@ func (doNothingAdmission) Admit(ctx context.Context, a admission.Attributes, o a
3331
func (doNothingAdmission) Handles(o admission.Operation) bool { return false }
3432
func (doNothingAdmission) Validate() error { return nil }
3533

36-
type doNothingPluginInitialization struct{}
37-
38-
func (doNothingPluginInitialization) ValidateInitialization() error { return nil }
39-
4034
type WantsCloudConfigAdmissionPlugin struct {
4135
doNothingAdmission
4236
cloudConfig []byte
@@ -48,38 +42,11 @@ func (p *WantsCloudConfigAdmissionPlugin) SetCloudConfig(cloudConfig []byte) {
4842

4943
func TestCloudConfigAdmissionPlugin(t *testing.T) {
5044
cloudConfig := []byte("cloud-configuration")
51-
initializer := NewPluginInitializer(cloudConfig, nil, nil)
45+
initializer := NewPluginInitializer(cloudConfig)
5246
wantsCloudConfigAdmission := &WantsCloudConfigAdmissionPlugin{}
5347
initializer.Initialize(wantsCloudConfigAdmission)
5448

5549
if wantsCloudConfigAdmission.cloudConfig == nil {
5650
t.Errorf("Expected cloud config to be initialized but found nil")
5751
}
5852
}
59-
60-
type doNothingQuotaConfiguration struct{}
61-
62-
func (doNothingQuotaConfiguration) IgnoredResources() map[schema.GroupResource]struct{} { return nil }
63-
64-
func (doNothingQuotaConfiguration) Evaluators() []quota.Evaluator { return nil }
65-
66-
type WantsQuotaConfigurationAdmissionPlugin struct {
67-
doNothingAdmission
68-
doNothingPluginInitialization
69-
config quota.Configuration
70-
}
71-
72-
func (p *WantsQuotaConfigurationAdmissionPlugin) SetQuotaConfiguration(config quota.Configuration) {
73-
p.config = config
74-
}
75-
76-
func TestQuotaConfigurationAdmissionPlugin(t *testing.T) {
77-
config := doNothingQuotaConfiguration{}
78-
initializer := NewPluginInitializer(nil, config, nil)
79-
wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{}
80-
initializer.Initialize(wantsQuotaConfigurationAdmission)
81-
82-
if wantsQuotaConfigurationAdmission.config == nil {
83-
t.Errorf("Expected quota configuration to be initialized but found nil")
84-
}
85-
}

0 commit comments

Comments
 (0)