From 3fbfd7eb1b355f377beef2fd2deb31682b801caa Mon Sep 17 00:00:00 2001 From: Paco Xu Date: Mon, 7 Mar 2022 15:40:02 +0800 Subject: [PATCH] add deprecated warning for node beta labels in pv/sc/rc/csi storage capacity - (pv) deprecated label using warning for node affinity - (storageclass) deprecated node labels: allowedTopologies.matchLabelExpressions.key - (CSIStorageCapacity) deprecated node labels - (RuntimeClass) deprecated node labels --- hack/.import-aliases | 1 + pkg/api/node/util.go | 48 ++++++++++++ pkg/api/persistentvolume/util.go | 52 ++++++++----- pkg/api/pod/warnings.go | 17 ++--- pkg/api/storage/util.go | 73 +++++++++++++++++++ .../core/persistentvolume/strategy.go | 4 +- pkg/registry/node/runtimeclass/strategy.go | 7 +- .../storage/csistoragecapacity/strategy.go | 5 +- pkg/registry/storage/storageclass/strategy.go | 5 +- 9 files changed, 173 insertions(+), 39 deletions(-) create mode 100644 pkg/api/node/util.go create mode 100644 pkg/api/storage/util.go diff --git a/hack/.import-aliases b/hack/.import-aliases index ea5bbde09b0..680b4dbb94e 100644 --- a/hack/.import-aliases +++ b/hack/.import-aliases @@ -41,6 +41,7 @@ "k8s.io/api/storage/v1beta1": "storagev1beta1", "k8s.io/apimachinery/pkg/api/errors": "apierrors", "k8s.io/component-helpers/node/util": "nodeutil", + "k8s.io/kubernetes/pkg/api/node": "nodeapi", "k8s.io/kubernetes/pkg/controller/util/node": "controllerutil", "k8s.io/kubelet/apis/stats/v1alpha1": "kubeletstatsv1alpha1", "k8s.io/kubernetes/pkg/controller/apis/config/v1alpha1": "controllerconfigv1alpha1", diff --git a/pkg/api/node/util.go b/pkg/api/node/util.go new file mode 100644 index 00000000000..0d593b9357a --- /dev/null +++ b/pkg/api/node/util.go @@ -0,0 +1,48 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package persistentvolume + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/kubernetes/pkg/apis/node" +) + +var DeprecatedNodeLabels = map[string]string{ + `beta.kubernetes.io/arch`: `deprecated since v1.14; use "kubernetes.io/arch" instead`, + `beta.kubernetes.io/os`: `deprecated since v1.14; use "kubernetes.io/os" instead`, + `failure-domain.beta.kubernetes.io/region`: `deprecated since v1.17; use "topology.kubernetes.io/region" instead`, + `failure-domain.beta.kubernetes.io/zone`: `deprecated since v1.17; use "topology.kubernetes.io/zone" instead`, + `beta.kubernetes.io/instance-type`: `deprecated since v1.17; use "node.kubernetes.io/instance-type" instead`, +} + +func GetWarningsForRuntimeClass(ctx context.Context, rc *node.RuntimeClass) []string { + var warnings []string + + if rc != nil { + // use of deprecated node labels in scheduling's node affinity + for key, _ := range rc.Scheduling.NodeSelector { + if msg, deprecated := DeprecatedNodeLabels[key]; deprecated { + warnings = append(warnings, fmt.Sprintf("%s: %s", field.NewPath("scheduling", "nodeSelector"), msg)) + } + } + } + + return warnings +} diff --git a/pkg/api/persistentvolume/util.go b/pkg/api/persistentvolume/util.go index 844e709417e..d0108180864 100644 --- a/pkg/api/persistentvolume/util.go +++ b/pkg/api/persistentvolume/util.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright 2022 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,28 +17,42 @@ limitations under the License. package persistentvolume import ( - utilfeature "k8s.io/apiserver/pkg/util/feature" + "context" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + nodeapi "k8s.io/kubernetes/pkg/api/node" api "k8s.io/kubernetes/pkg/apis/core" - "k8s.io/kubernetes/pkg/features" ) -// DropDisabledFields removes disabled fields from the pv spec. -// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a pv spec. -func DropDisabledFields(pvSpec *api.PersistentVolumeSpec, oldPVSpec *api.PersistentVolumeSpec) { - if !utilfeature.DefaultFeatureGate.Enabled(features.CSINodeExpandSecret) && !hasNodeExpansionSecrets(oldPVSpec) { - if pvSpec.CSI != nil { - pvSpec.CSI.NodeExpandSecretRef = nil +func GetWarningsForPersistentVolume(ctx context.Context, pv *api.PersistentVolume) []string { + if pv == nil { + return nil + } + return warningsForPersistentVolumeSpecAndMeta(nil, &pv.Spec, &pv.ObjectMeta) +} + +func warningsForPersistentVolumeSpecAndMeta(fieldPath *field.Path, pvSpec *api.PersistentVolumeSpec, meta *metav1.ObjectMeta) []string { + var warnings []string + + // use of deprecated node labels in node affinity + for i, k := range pvSpec.NodeAffinity.Required.NodeSelectorTerms { + expressions := k.MatchExpressions + for j, e := range expressions { + if msg, deprecated := nodeapi.DeprecatedNodeLabels[e.Key]; deprecated { + warnings = append( + warnings, + fmt.Sprintf( + "%s: %s is %s", + fieldPath.Child("spec", "NodeAffinity").Child("Required").Child("NodeSelectorTerms").Index(i).Child("MatchExpressions").Index(j).Child("key"), + e.Key, + msg, + ), + ) + } } } -} -func hasNodeExpansionSecrets(oldPVSpec *api.PersistentVolumeSpec) bool { - if oldPVSpec == nil || oldPVSpec.CSI == nil { - return false - } - - if oldPVSpec.CSI.NodeExpandSecretRef != nil { - return true - } - return false + return warnings } diff --git a/pkg/api/pod/warnings.go b/pkg/api/pod/warnings.go index 3a9328f9193..f7429798e27 100644 --- a/pkg/api/pod/warnings.go +++ b/pkg/api/pod/warnings.go @@ -24,6 +24,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" + nodeapi "k8s.io/kubernetes/pkg/api/node" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core/pods" ) @@ -60,14 +61,6 @@ func GetWarningsForPodTemplate(ctx context.Context, fieldPath *field.Path, podTe return warningsForPodSpecAndMeta(fieldPath, &podTemplate.Spec, &podTemplate.ObjectMeta, oldSpec, oldMeta) } -var deprecatedNodeLabels = map[string]string{ - `beta.kubernetes.io/arch`: `deprecated since v1.14; use "kubernetes.io/arch" instead`, - `beta.kubernetes.io/os`: `deprecated since v1.14; use "kubernetes.io/os" instead`, - `failure-domain.beta.kubernetes.io/region`: `deprecated since v1.17; use "topology.kubernetes.io/region" instead`, - `failure-domain.beta.kubernetes.io/zone`: `deprecated since v1.17; use "topology.kubernetes.io/zone" instead`, - `beta.kubernetes.io/instance-type`: `deprecated since v1.17; use "node.kubernetes.io/instance-type" instead`, -} - var deprecatedAnnotations = []struct { key string prefix string @@ -92,7 +85,7 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta // use of deprecated node labels in selectors/affinity/topology for k := range podSpec.NodeSelector { - if msg, deprecated := deprecatedNodeLabels[k]; deprecated { + if msg, deprecated := nodeapi.DeprecatedNodeLabels[k]; deprecated { warnings = append(warnings, fmt.Sprintf("%s: %s", fieldPath.Child("spec", "nodeSelector").Key(k), msg)) } } @@ -101,7 +94,7 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta if n.RequiredDuringSchedulingIgnoredDuringExecution != nil { for i, t := range n.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms { for j, e := range t.MatchExpressions { - if msg, deprecated := deprecatedNodeLabels[e.Key]; deprecated { + if msg, deprecated := nodeapi.DeprecatedNodeLabels[e.Key]; deprecated { warnings = append( warnings, fmt.Sprintf( @@ -119,7 +112,7 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta } for i, t := range n.PreferredDuringSchedulingIgnoredDuringExecution { for j, e := range t.Preference.MatchExpressions { - if msg, deprecated := deprecatedNodeLabels[e.Key]; deprecated { + if msg, deprecated := nodeapi.DeprecatedNodeLabels[e.Key]; deprecated { warnings = append( warnings, fmt.Sprintf( @@ -137,7 +130,7 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta } } for i, t := range podSpec.TopologySpreadConstraints { - if msg, deprecated := deprecatedNodeLabels[t.TopologyKey]; deprecated { + if msg, deprecated := nodeapi.DeprecatedNodeLabels[t.TopologyKey]; deprecated { warnings = append(warnings, fmt.Sprintf( "%s: %s is %s", fieldPath.Child("spec", "topologySpreadConstraints").Index(i).Child("topologyKey"), diff --git a/pkg/api/storage/util.go b/pkg/api/storage/util.go new file mode 100644 index 00000000000..84ee5d185b8 --- /dev/null +++ b/pkg/api/storage/util.go @@ -0,0 +1,73 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package storage + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/util/validation/field" + nodeapi "k8s.io/kubernetes/pkg/api/node" + "k8s.io/kubernetes/pkg/apis/storage" +) + +func GetWarningsForStorageClass(ctx context.Context, sc *storage.StorageClass) []string { + var warnings []string + + if sc != nil { + // use of deprecated node labels in allowedTopologies's matchLabelExpressions + for i, topo := range sc.AllowedTopologies { + for j, expression := range topo.MatchLabelExpressions { + if msg, deprecated := nodeapi.DeprecatedNodeLabels[expression.Key]; deprecated { + warnings = append(warnings, fmt.Sprintf("%s: %s", field.NewPath("allowedTopologies").Index(i).Child("matchLabelExpressions").Index(j), msg)) + } + } + } + } + + return warnings +} + +func GetWarningsForCSIStorageCapacity(ctx context.Context, csc *storage.CSIStorageCapacity) []string { + var warnings []string + + if csc != nil { + // use of deprecated node labels in allowedTopologies's matchLabelExpressions + for i, expression := range csc.NodeTopology.MatchExpressions { + if msg, deprecated := nodeapi.DeprecatedNodeLabels[expression.Key]; deprecated { + warnings = append( + warnings, + fmt.Sprintf( + "%s: %s is %s", + field.NewPath("nodeTopology").Child("matchExpressions").Index(i), + expression.Key, + msg, + ), + ) + } + } + + // use of deprecated node labels in allowedTopologies's matchLabels + for label, _ := range csc.NodeTopology.MatchLabels { + if msg, deprecated := nodeapi.DeprecatedNodeLabels[label]; deprecated { + warnings = append(warnings, fmt.Sprintf("%s: %s", field.NewPath("nodeTopology").Child("matchLabels").Child(label), msg)) + } + } + } + + return warnings +} diff --git a/pkg/registry/core/persistentvolume/strategy.go b/pkg/registry/core/persistentvolume/strategy.go index 89b5a0332fd..a9e190f7964 100644 --- a/pkg/registry/core/persistentvolume/strategy.go +++ b/pkg/registry/core/persistentvolume/strategy.go @@ -78,7 +78,7 @@ func (persistentvolumeStrategy) Validate(ctx context.Context, obj runtime.Object // WarningsOnCreate returns warnings for the creation of the given object. func (persistentvolumeStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { - return nil + return pvutil.GetWarningsForPersistentVolume(ctx, obj.(*api.PersistentVolume)) } // Canonicalize normalizes the object after validation. @@ -109,7 +109,7 @@ func (persistentvolumeStrategy) ValidateUpdate(ctx context.Context, obj, old run // WarningsOnUpdate returns warnings for the given update. func (persistentvolumeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { - return nil + return pvutil.GetWarningsForPersistentVolume(ctx, obj.(*api.PersistentVolume)) } func (persistentvolumeStrategy) AllowUnconditionalUpdate() bool { diff --git a/pkg/registry/node/runtimeclass/strategy.go b/pkg/registry/node/runtimeclass/strategy.go index 4d0a8051446..995d7b5e271 100644 --- a/pkg/registry/node/runtimeclass/strategy.go +++ b/pkg/registry/node/runtimeclass/strategy.go @@ -24,6 +24,7 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" + nodeapi "k8s.io/kubernetes/pkg/api/node" "k8s.io/kubernetes/pkg/apis/node" "k8s.io/kubernetes/pkg/apis/node/validation" ) @@ -73,7 +74,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis } // WarningsOnCreate returns warnings for the creation of the given object. -func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil } +func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { + return nodeapi.GetWarningsForRuntimeClass(ctx, obj.(*node.RuntimeClass)) +} // Canonicalize normalizes the object after validation. func (strategy) Canonicalize(obj runtime.Object) { @@ -89,7 +92,7 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie // WarningsOnUpdate returns warnings for the given update. func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { - return nil + return nodeapi.GetWarningsForRuntimeClass(ctx, obj.(*node.RuntimeClass)) } // If AllowUnconditionalUpdate() is true and the object specified by diff --git a/pkg/registry/storage/csistoragecapacity/strategy.go b/pkg/registry/storage/csistoragecapacity/strategy.go index 5e294fbe254..95df1945b4d 100644 --- a/pkg/registry/storage/csistoragecapacity/strategy.go +++ b/pkg/registry/storage/csistoragecapacity/strategy.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" + storageutil "k8s.io/kubernetes/pkg/api/storage" "k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/apis/storage/validation" ) @@ -56,7 +57,7 @@ func (csiStorageCapacityStrategy) Validate(ctx context.Context, obj runtime.Obje // WarningsOnCreate returns warnings for the creation of the given object. func (csiStorageCapacityStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { - return nil + return storageutil.GetWarningsForCSIStorageCapacity(ctx, obj.(*storage.CSIStorageCapacity)) } // Canonicalize normalizes the object after validation. @@ -80,7 +81,7 @@ func (csiStorageCapacityStrategy) ValidateUpdate(ctx context.Context, obj, old r // WarningsOnUpdate returns warnings for the given update. func (csiStorageCapacityStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { - return nil + return storageutil.GetWarningsForCSIStorageCapacity(ctx, obj.(*storage.CSIStorageCapacity)) } func (csiStorageCapacityStrategy) AllowUnconditionalUpdate() bool { diff --git a/pkg/registry/storage/storageclass/strategy.go b/pkg/registry/storage/storageclass/strategy.go index a73f9067925..5c540e5fb84 100644 --- a/pkg/registry/storage/storageclass/strategy.go +++ b/pkg/registry/storage/storageclass/strategy.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" + storageutil2 "k8s.io/kubernetes/pkg/api/storage" "k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/apis/storage/validation" ) @@ -52,7 +53,7 @@ func (storageClassStrategy) Validate(ctx context.Context, obj runtime.Object) fi // WarningsOnCreate returns warnings for the creation of the given object. func (storageClassStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { - return nil + return storageutil2.GetWarningsForStorageClass(ctx, obj.(*storage.StorageClass)) } // Canonicalize normalizes the object after validation. @@ -74,7 +75,7 @@ func (storageClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime // WarningsOnUpdate returns warnings for the given update. func (storageClassStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { - return nil + return storageutil2.GetWarningsForStorageClass(ctx, obj.(*storage.StorageClass)) } func (storageClassStrategy) AllowUnconditionalUpdate() bool {