Skip to content

Commit 227fc7a

Browse files
committed
Remove more defaulting from KubeadmConfig/KubeadmConfigTemplate/KCP/KCPTemplate
1 parent cb05ce9 commit 227fc7a

File tree

28 files changed

+203
-229
lines changed

28 files changed

+203
-229
lines changed

api/bootstrap/kubeadm/v1beta2/kubeadmconfig_types.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -134,28 +134,6 @@ type KubeadmConfigSpec struct {
134134
Ignition *IgnitionSpec `json:"ignition,omitempty"`
135135
}
136136

137-
// Default defaults a KubeadmConfigSpec.
138-
func (c *KubeadmConfigSpec) Default() {
139-
if c.Format == "" {
140-
c.Format = CloudConfig
141-
}
142-
if c.InitConfiguration != nil && c.InitConfiguration.NodeRegistration.ImagePullPolicy == "" {
143-
c.InitConfiguration.NodeRegistration.ImagePullPolicy = "IfNotPresent"
144-
}
145-
if c.JoinConfiguration != nil && c.JoinConfiguration.NodeRegistration.ImagePullPolicy == "" {
146-
c.JoinConfiguration.NodeRegistration.ImagePullPolicy = "IfNotPresent"
147-
}
148-
if c.JoinConfiguration != nil && c.JoinConfiguration.Discovery.File != nil {
149-
if kfg := c.JoinConfiguration.Discovery.File.KubeConfig; kfg != nil {
150-
if kfg.User.Exec != nil {
151-
if kfg.User.Exec.APIVersion == "" {
152-
kfg.User.Exec.APIVersion = "client.authentication.k8s.io/v1"
153-
}
154-
}
155-
}
156-
}
157-
}
158-
159137
// Validate ensures the KubeadmConfigSpec is valid.
160138
func (c *KubeadmConfigSpec) Validate(pathPrefix *field.Path) field.ErrorList {
161139
var allErrs field.ErrorList

bootstrap/kubeadm/config/webhook/manifests.yaml

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,6 @@ kind: MutatingWebhookConfiguration
44
metadata:
55
name: mutating-webhook-configuration
66
webhooks:
7-
- admissionReviewVersions:
8-
- v1
9-
- v1beta1
10-
clientConfig:
11-
service:
12-
name: webhook-service
13-
namespace: system
14-
path: /mutate-bootstrap-cluster-x-k8s-io-v1beta2-kubeadmconfig
15-
failurePolicy: Fail
16-
name: default.kubeadmconfig.bootstrap.cluster.x-k8s.io
17-
rules:
18-
- apiGroups:
19-
- bootstrap.cluster.x-k8s.io
20-
apiVersions:
21-
- v1beta2
22-
operations:
23-
- CREATE
24-
- UPDATE
25-
resources:
26-
- kubeadmconfigs
27-
sideEffects: None
287
- admissionReviewVersions:
298
- v1
309
- v1beta1
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
Copyright 2021 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 defaulting contains defaulting code that is used in CABPK and KCP.
18+
package defaulting
19+
20+
import bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2"
21+
22+
// ApplyPreviousKubeadmConfigDefaults defaults a KubeadmConfig with default values we used in the past.
23+
// This is done in multiple places (webhooks and KCP controller) to ensure no rollouts are triggered now that
24+
// we removed this defaulting from webhooks.
25+
func ApplyPreviousKubeadmConfigDefaults(c *bootstrapv1.KubeadmConfigSpec) {
26+
if c.Format == "" {
27+
c.Format = bootstrapv1.CloudConfig
28+
}
29+
if c.InitConfiguration != nil && c.InitConfiguration.NodeRegistration.ImagePullPolicy == "" {
30+
c.InitConfiguration.NodeRegistration.ImagePullPolicy = "IfNotPresent"
31+
}
32+
if c.JoinConfiguration != nil && c.JoinConfiguration.NodeRegistration.ImagePullPolicy == "" {
33+
c.JoinConfiguration.NodeRegistration.ImagePullPolicy = "IfNotPresent"
34+
}
35+
if c.JoinConfiguration != nil && c.JoinConfiguration.Discovery.File != nil {
36+
if kfg := c.JoinConfiguration.Discovery.File.KubeConfig; kfg != nil {
37+
if kfg.User.Exec != nil {
38+
if kfg.User.Exec.APIVersion == "" {
39+
kfg.User.Exec.APIVersion = "client.authentication.k8s.io/v1"
40+
}
41+
}
42+
}
43+
}
44+
}

bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,10 +1053,14 @@ func (r *KubeadmConfigReconciler) resolveDiscoveryKubeConfig(cfg *bootstrapv1.Fi
10531053
}
10541054
}
10551055
if cfg.KubeConfig.User.Exec != nil {
1056+
apiVersion := cfg.KubeConfig.User.Exec.APIVersion
1057+
if apiVersion == "" {
1058+
apiVersion = "client.authentication.k8s.io/v1"
1059+
}
10561060
user.Exec = &clientcmdv1.ExecConfig{
10571061
Command: cfg.KubeConfig.User.Exec.Command,
10581062
Args: cfg.KubeConfig.User.Exec.Args,
1059-
APIVersion: cfg.KubeConfig.User.Exec.APIVersion,
1063+
APIVersion: apiVersion,
10601064
ProvideClusterInfo: ptr.Deref(cfg.KubeConfig.User.Exec.ProvideClusterInfo, false),
10611065
InteractiveMode: "Never",
10621066
}
@@ -1356,6 +1360,11 @@ func (r *KubeadmConfigReconciler) computeClusterConfigurationAndAdditionalData(c
13561360
func (r *KubeadmConfigReconciler) storeBootstrapData(ctx context.Context, scope *Scope, data []byte) error {
13571361
log := ctrl.LoggerFrom(ctx)
13581362

1363+
format := scope.Config.Spec.Format
1364+
if format == "" {
1365+
format = bootstrapv1.CloudConfig
1366+
}
1367+
13591368
secret := &corev1.Secret{
13601369
ObjectMeta: metav1.ObjectMeta{
13611370
Name: scope.Config.Name,
@@ -1375,7 +1384,7 @@ func (r *KubeadmConfigReconciler) storeBootstrapData(ctx context.Context, scope
13751384
},
13761385
Data: map[string][]byte{
13771386
"value": data,
1378-
"format": []byte(scope.Config.Spec.Format),
1387+
"format": []byte(format),
13791388
},
13801389
Type: clusterv1.ClusterSecretType,
13811390
}

bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,8 @@ func TestBootstrapDataFormat(t *testing.T) {
827827
clusterInitialized: true,
828828
},
829829
{
830-
name: "Empty format field",
830+
name: "Empty format field",
831+
format: bootstrapv1.CloudConfig,
831832
},
832833
}
833834

@@ -2315,8 +2316,7 @@ func TestKubeadmConfigReconciler_ResolveDiscoveryFileKubeConfig(t *testing.T) {
23152316
KubeConfig: &bootstrapv1.FileDiscoveryKubeConfig{
23162317
User: bootstrapv1.KubeConfigUser{
23172318
Exec: &bootstrapv1.KubeConfigAuthExec{
2318-
APIVersion: "client.authentication.k8s.io/v1",
2319-
Command: "/usr/bin/bootstrap",
2319+
Command: "/usr/bin/bootstrap",
23202320
Env: []bootstrapv1.KubeConfigAuthExecEnv{
23212321
{Name: "ENV_TEST", Value: "value"},
23222322
},

bootstrap/kubeadm/internal/webhooks/kubeadmconfig.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,31 +33,16 @@ import (
3333
func (webhook *KubeadmConfig) SetupWebhookWithManager(mgr ctrl.Manager) error {
3434
return ctrl.NewWebhookManagedBy(mgr).
3535
For(&bootstrapv1.KubeadmConfig{}).
36-
WithDefaulter(webhook).
3736
WithValidator(webhook).
3837
Complete()
3938
}
4039

41-
// +kubebuilder:webhook:verbs=create;update,path=/mutate-bootstrap-cluster-x-k8s-io-v1beta2-kubeadmconfig,mutating=true,failurePolicy=fail,groups=bootstrap.cluster.x-k8s.io,resources=kubeadmconfigs,versions=v1beta2,name=default.kubeadmconfig.bootstrap.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
4240
// +kubebuilder:webhook:verbs=create;update,path=/validate-bootstrap-cluster-x-k8s-io-v1beta2-kubeadmconfig,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=bootstrap.cluster.x-k8s.io,resources=kubeadmconfigs,versions=v1beta2,name=validation.kubeadmconfig.bootstrap.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
4341

4442
// KubeadmConfig implements a validation and defaulting webhook for KubeadmConfig.
4543
type KubeadmConfig struct{}
4644

4745
var _ webhook.CustomValidator = &KubeadmConfig{}
48-
var _ webhook.CustomDefaulter = &KubeadmConfig{}
49-
50-
// Default implements webhook.Defaulter so a webhook will be registered for the type.
51-
func (webhook *KubeadmConfig) Default(_ context.Context, obj runtime.Object) error {
52-
c, ok := obj.(*bootstrapv1.KubeadmConfig)
53-
if !ok {
54-
return apierrors.NewBadRequest(fmt.Sprintf("expected a KubeadmConfig but got a %T", obj))
55-
}
56-
57-
c.Spec.Default()
58-
59-
return nil
60-
}
6146

6247
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
6348
func (webhook *KubeadmConfig) ValidateCreate(_ context.Context, obj runtime.Object) (admission.Warnings, error) {

bootstrap/kubeadm/internal/webhooks/kubeadmconfig_test.go

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,10 @@ import (
2727

2828
bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2"
2929
"sigs.k8s.io/cluster-api/feature"
30-
"sigs.k8s.io/cluster-api/internal/webhooks/util"
3130
)
3231

3332
var ctx = ctrl.SetupSignalHandler()
3433

35-
func TestKubeadmConfigDefault(t *testing.T) {
36-
utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)
37-
38-
g := NewWithT(t)
39-
40-
kubeadmConfig := &bootstrapv1.KubeadmConfig{
41-
ObjectMeta: metav1.ObjectMeta{
42-
Namespace: "foo",
43-
},
44-
Spec: bootstrapv1.KubeadmConfigSpec{},
45-
}
46-
updateDefaultingKubeadmConfig := kubeadmConfig.DeepCopy()
47-
updateDefaultingKubeadmConfig.Spec.Verbosity = ptr.To[int32](4)
48-
webhook := &KubeadmConfig{}
49-
t.Run("for KubeadmConfig", util.CustomDefaultValidateTest(ctx, updateDefaultingKubeadmConfig, webhook))
50-
51-
g.Expect(webhook.Default(ctx, kubeadmConfig)).To(Succeed())
52-
53-
g.Expect(kubeadmConfig.Spec.Format).To(Equal(bootstrapv1.CloudConfig))
54-
55-
ignitionKubeadmConfig := &bootstrapv1.KubeadmConfig{
56-
ObjectMeta: metav1.ObjectMeta{
57-
Namespace: "foo",
58-
},
59-
Spec: bootstrapv1.KubeadmConfigSpec{
60-
Format: bootstrapv1.Ignition,
61-
},
62-
}
63-
g.Expect(webhook.Default(ctx, ignitionKubeadmConfig)).To(Succeed())
64-
g.Expect(ignitionKubeadmConfig.Spec.Format).To(Equal(bootstrapv1.Ignition))
65-
}
66-
6734
func TestKubeadmConfigValidate(t *testing.T) {
6835
cases := map[string]struct {
6936
in *bootstrapv1.KubeadmConfig

bootstrap/kubeadm/internal/webhooks/kubeadmconfigtemplate.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2828

2929
bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2"
30+
"sigs.k8s.io/cluster-api/bootstrap/kubeadm/defaulting"
31+
"sigs.k8s.io/cluster-api/util/topology"
3032
)
3133

3234
func (webhook *KubeadmConfigTemplate) SetupWebhookWithManager(mgr ctrl.Manager) error {
@@ -44,13 +46,20 @@ func (webhook *KubeadmConfigTemplate) SetupWebhookWithManager(mgr ctrl.Manager)
4446
type KubeadmConfigTemplate struct{}
4547

4648
// Default implements webhook.Defaulter so a webhook will be registered for the type.
47-
func (webhook *KubeadmConfigTemplate) Default(_ context.Context, obj runtime.Object) error {
49+
func (webhook *KubeadmConfigTemplate) Default(ctx context.Context, obj runtime.Object) error {
4850
c, ok := obj.(*bootstrapv1.KubeadmConfigTemplate)
4951
if !ok {
5052
return apierrors.NewBadRequest(fmt.Sprintf("expected a KubeadmConfigTemplate but got a %T", obj))
5153
}
5254

53-
c.Spec.Template.Spec.Default()
55+
req, err := admission.RequestFromContext(ctx)
56+
if err != nil {
57+
return apierrors.NewBadRequest(fmt.Sprintf("expected an admission.Request inside context: %v", err))
58+
}
59+
60+
if topology.IsDryRunRequest(req, c) {
61+
defaulting.ApplyPreviousKubeadmConfigDefaults(&c.Spec.Template.Spec)
62+
}
5463

5564
return nil
5665
}

bootstrap/kubeadm/internal/webhooks/kubeadmconfigtemplate_test.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ import (
2121
"testing"
2222

2323
. "github.com/onsi/gomega"
24+
admissionv1 "k8s.io/api/admission/v1"
2425
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2526
"k8s.io/utils/ptr"
27+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2628

2729
bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2"
2830
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
@@ -40,10 +42,23 @@ func TestKubeadmConfigTemplateDefault(t *testing.T) {
4042
updateDefaultingKubeadmConfigTemplate := kubeadmConfigTemplate.DeepCopy()
4143
updateDefaultingKubeadmConfigTemplate.Spec.Template.Spec.Verbosity = ptr.To[int32](4)
4244
webhook := &KubeadmConfigTemplate{}
43-
t.Run("for KubeadmConfigTemplate", util.CustomDefaultValidateTest(ctx, updateDefaultingKubeadmConfigTemplate, webhook))
45+
t.Run("for KubeadmConfigTemplate", util.CustomDefaultValidateTest(admission.NewContextWithRequest(ctx, admission.Request{}), updateDefaultingKubeadmConfigTemplate, webhook))
4446

45-
g.Expect(webhook.Default(ctx, kubeadmConfigTemplate)).To(Succeed())
47+
// Expect no defaulting.
48+
original := kubeadmConfigTemplate.DeepCopy()
49+
g.Expect(webhook.Default(admission.NewContextWithRequest(ctx, admission.Request{}), kubeadmConfigTemplate)).To(Succeed())
50+
g.Expect(kubeadmConfigTemplate).To(BeComparableTo(original))
4651

52+
// Expect defaulting for dry-run request.
53+
ctx = admission.NewContextWithRequest(ctx, admission.Request{
54+
AdmissionRequest: admissionv1.AdmissionRequest{
55+
DryRun: ptr.To(true),
56+
},
57+
})
58+
kubeadmConfigTemplate.Annotations = map[string]string{
59+
clusterv1.TopologyDryRunAnnotation: "",
60+
}
61+
g.Expect(webhook.Default(ctx, kubeadmConfigTemplate)).To(Succeed())
4762
g.Expect(kubeadmConfigTemplate.Spec.Template.Spec.Format).To(Equal(bootstrapv1.CloudConfig))
4863
}
4964

controllers/external/util.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ type GenerateTemplateInput struct {
193193
func GenerateTemplate(in *GenerateTemplateInput) (*unstructured.Unstructured, error) {
194194
template, found, err := unstructured.NestedMap(in.Template.Object, "spec", "template")
195195
if !found {
196-
return nil, errors.Errorf("missing Spec.Template on %v %q", in.Template.GroupVersionKind(), in.Template.GetName())
196+
// If spec.template is not set we are intentionally using an empty object here.
197+
template = nil
197198
} else if err != nil {
198199
return nil, errors.Wrapf(err, "failed to retrieve Spec.Template map on %v %q", in.Template.GroupVersionKind(), in.Template.GetName())
199200
}

0 commit comments

Comments
 (0)