diff --git a/pkg/api/node/util.go b/pkg/api/node/util.go new file mode 100644 index 00000000000..fcc6dba4145 --- /dev/null +++ b/pkg/api/node/util.go @@ -0,0 +1,108 @@ +/* +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 node + +import ( + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + api "k8s.io/kubernetes/pkg/apis/core" + "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`, +} + +// GetNodeLabelDeprecatedMessage returns the message for the deprecated node label +// and a bool indicating if the label is deprecated. +func GetNodeLabelDeprecatedMessage(key string) (string, bool) { + msg, ok := deprecatedNodeLabels[key] + return msg, ok +} + +func GetWarningsForRuntimeClass(rc *node.RuntimeClass) []string { + var warnings []string + + if rc != nil && rc.Scheduling != nil && rc.Scheduling.NodeSelector != nil { + // use of deprecated node labels in scheduling's node affinity + for key := range rc.Scheduling.NodeSelector { + if msg, deprecated := GetNodeLabelDeprecatedMessage(key); deprecated { + warnings = append(warnings, fmt.Sprintf("%s: %s", field.NewPath("scheduling", "nodeSelector"), msg)) + } + } + } + + return warnings +} + +// GetWarningsForNodeSelector tests if any of the node selector requirements in the template is deprecated. +// If there are deprecated node selector requirements in either match expressions or match labels, a warning is returned. +func GetWarningsForNodeSelector(nodeSelector *metav1.LabelSelector, fieldPath *field.Path) []string { + if nodeSelector == nil { + return nil + } + + var warnings []string + // use of deprecated node labels in matchLabelExpressions + for i, expression := range nodeSelector.MatchExpressions { + if msg, deprecated := GetNodeLabelDeprecatedMessage(expression.Key); deprecated { + warnings = append( + warnings, + fmt.Sprintf( + "%s: %s is %s", + fieldPath.Child("matchExpressions").Index(i).Child("key"), + expression.Key, + msg, + ), + ) + } + } + + // use of deprecated node labels in matchLabels + for label := range nodeSelector.MatchLabels { + if msg, deprecated := GetNodeLabelDeprecatedMessage(label); deprecated { + warnings = append(warnings, fmt.Sprintf("%s: %s", fieldPath.Child("matchLabels").Child(label), msg)) + } + } + return warnings +} + +// GetWarningsForNodeSelectorTerm checks match expressions of node selector term +func GetWarningsForNodeSelectorTerm(nodeSelectorTerm api.NodeSelectorTerm, fieldPath *field.Path) []string { + var warnings []string + // use of deprecated node labels in matchLabelExpressions + for i, expression := range nodeSelectorTerm.MatchExpressions { + if msg, deprecated := GetNodeLabelDeprecatedMessage(expression.Key); deprecated { + warnings = append( + warnings, + fmt.Sprintf( + "%s: %s is %s", + fieldPath.Child("matchExpressions").Index(i).Child("key"), + expression.Key, + msg, + ), + ) + } + } + return warnings +} diff --git a/pkg/api/node/util_test.go b/pkg/api/node/util_test.go new file mode 100644 index 00000000000..02b1fd152f6 --- /dev/null +++ b/pkg/api/node/util_test.go @@ -0,0 +1,81 @@ +/* +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 node + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" + + "k8s.io/kubernetes/pkg/apis/node" +) + +func TestWarnings(t *testing.T) { + testcases := []struct { + name string + template *node.RuntimeClass + expected []string + }{ + { + name: "null", + template: nil, + expected: nil, + }, + { + name: "no warning", + template: &node.RuntimeClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + }, + expected: nil, + }, + { + name: "warning", + template: &node.RuntimeClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Scheduling: &node.Scheduling{ + NodeSelector: map[string]string{ + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/os": "linux", + }, + }, + }, + expected: []string{ + `scheduling.nodeSelector: deprecated since v1.14; use "kubernetes.io/arch" instead`, + `scheduling.nodeSelector: deprecated since v1.14; use "kubernetes.io/os" instead`, + }, + }, + } + + for _, tc := range testcases { + t.Run("podspec_"+tc.name, func(t *testing.T) { + actual := sets.NewString(GetWarningsForRuntimeClass(tc.template)...) + expected := sets.NewString(tc.expected...) + for _, missing := range expected.Difference(actual).List() { + t.Errorf("missing: %s", missing) + } + for _, extra := range actual.Difference(expected).List() { + t.Errorf("extra: %s", extra) + } + }) + + } +} diff --git a/pkg/api/persistentvolume/util.go b/pkg/api/persistentvolume/util.go index 844e709417e..29862d73d5b 100644 --- a/pkg/api/persistentvolume/util.go +++ b/pkg/api/persistentvolume/util.go @@ -17,7 +17,9 @@ limitations under the License. package persistentvolume import ( + "k8s.io/apimachinery/pkg/util/validation/field" utilfeature "k8s.io/apiserver/pkg/util/feature" + nodeapi "k8s.io/kubernetes/pkg/api/node" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/features" ) @@ -42,3 +44,24 @@ func hasNodeExpansionSecrets(oldPVSpec *api.PersistentVolumeSpec) bool { } return false } + +func GetWarningsForPersistentVolume(pv *api.PersistentVolume) []string { + if pv == nil { + return nil + } + return warningsForPersistentVolumeSpecAndMeta(nil, &pv.Spec) +} + +func warningsForPersistentVolumeSpecAndMeta(fieldPath *field.Path, pvSpec *api.PersistentVolumeSpec) []string { + var warnings []string + + if pvSpec.NodeAffinity != nil && pvSpec.NodeAffinity.Required != nil { + termFldPath := fieldPath.Child("spec", "nodeAffinity", "required", "nodeSelectorTerms") + // use of deprecated node labels in node affinity + for i, term := range pvSpec.NodeAffinity.Required.NodeSelectorTerms { + warnings = append(warnings, nodeapi.GetWarningsForNodeSelectorTerm(term, termFldPath.Index(i))...) + } + } + + return warnings +} diff --git a/pkg/api/persistentvolume/util_test.go b/pkg/api/persistentvolume/util_test.go index 3874adb18c7..1838c054c38 100644 --- a/pkg/api/persistentvolume/util_test.go +++ b/pkg/api/persistentvolume/util_test.go @@ -22,6 +22,8 @@ import ( "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" api "k8s.io/kubernetes/pkg/apis/core" @@ -108,3 +110,74 @@ func specWithCSISecrets(secret *api.SecretReference) *api.PersistentVolumeSpec { } return pvSpec } + +func TestWarnings(t *testing.T) { + testcases := []struct { + name string + template *api.PersistentVolume + expected []string + }{ + { + name: "null", + template: nil, + expected: nil, + }, + { + name: "no warning", + template: &api.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Status: api.PersistentVolumeStatus{ + Phase: api.VolumeBound, + }, + }, + expected: nil, + }, + { + name: "warning", + template: &api.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: api.PersistentVolumeSpec{ + NodeAffinity: &api.VolumeNodeAffinity{ + Required: &api.NodeSelector{ + NodeSelectorTerms: []api.NodeSelectorTerm{ + { + MatchExpressions: []api.NodeSelectorRequirement{ + { + Key: "beta.kubernetes.io/os", + Operator: "Equal", + Values: []string{"windows"}, + }, + }, + }, + }, + }, + }, + }, + Status: api.PersistentVolumeStatus{ + Phase: api.VolumeBound, + }, + }, + expected: []string{ + `spec.nodeAffinity.required.nodeSelectorTerms[0].matchExpressions[0].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead`, + }, + }, + } + + for _, tc := range testcases { + t.Run("podspec_"+tc.name, func(t *testing.T) { + actual := sets.NewString(GetWarningsForPersistentVolume(tc.template)...) + expected := sets.NewString(tc.expected...) + for _, missing := range expected.Difference(actual).List() { + t.Errorf("missing: %s", missing) + } + for _, extra := range actual.Difference(expected).List() { + t.Errorf("extra: %s", extra) + } + }) + + } +} diff --git a/pkg/api/pod/warnings.go b/pkg/api/pod/warnings.go index 79f5db2f357..146f0cca61d 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,52 +85,25 @@ 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.GetNodeLabelDeprecatedMessage(k); deprecated { warnings = append(warnings, fmt.Sprintf("%s: %s", fieldPath.Child("spec", "nodeSelector").Key(k), msg)) } } if podSpec.Affinity != nil && podSpec.Affinity.NodeAffinity != nil { n := podSpec.Affinity.NodeAffinity if n.RequiredDuringSchedulingIgnoredDuringExecution != nil { - for i, t := range n.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms { - for j, e := range t.MatchExpressions { - if msg, deprecated := deprecatedNodeLabels[e.Key]; deprecated { - warnings = append( - warnings, - fmt.Sprintf( - "%s: %s is %s", - fieldPath.Child("spec", "affinity", "nodeAffinity", "requiredDuringSchedulingIgnoredDuringExecution", "nodeSelectorTerms").Index(i). - Child("matchExpressions").Index(j). - Child("key"), - e.Key, - msg, - ), - ) - } - } + termFldPath := fieldPath.Child("spec", "affinity", "nodeAffinity", "requiredDuringSchedulingIgnoredDuringExecution", "nodeSelectorTerms") + for i, term := range n.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms { + warnings = append(warnings, nodeapi.GetWarningsForNodeSelectorTerm(term, termFldPath.Index(i))...) } } - for i, t := range n.PreferredDuringSchedulingIgnoredDuringExecution { - for j, e := range t.Preference.MatchExpressions { - if msg, deprecated := deprecatedNodeLabels[e.Key]; deprecated { - warnings = append( - warnings, - fmt.Sprintf( - "%s: %s is %s", - fieldPath.Child("spec", "affinity", "nodeAffinity", "preferredDuringSchedulingIgnoredDuringExecution").Index(i). - Child("preference"). - Child("matchExpressions").Index(j). - Child("key"), - e.Key, - msg, - ), - ) - } - } + preferredFldPath := fieldPath.Child("spec", "affinity", "nodeAffinity", "preferredDuringSchedulingIgnoredDuringExecution") + for i, term := range n.PreferredDuringSchedulingIgnoredDuringExecution { + warnings = append(warnings, nodeapi.GetWarningsForNodeSelectorTerm(term.Preference, preferredFldPath.Index(i).Child("preference"))...) } } for i, t := range podSpec.TopologySpreadConstraints { - if msg, deprecated := deprecatedNodeLabels[t.TopologyKey]; deprecated { + if msg, deprecated := nodeapi.GetNodeLabelDeprecatedMessage(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..133d8b2b646 --- /dev/null +++ b/pkg/api/storage/util.go @@ -0,0 +1,49 @@ +/* +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 ( + "fmt" + + "k8s.io/apimachinery/pkg/util/validation/field" + nodeapi "k8s.io/kubernetes/pkg/api/node" + "k8s.io/kubernetes/pkg/apis/storage" +) + +func GetWarningsForStorageClass(sc *storage.StorageClass) []string { + var warnings []string + + if sc != nil && sc.AllowedTopologies != 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.GetNodeLabelDeprecatedMessage(expression.Key); deprecated { + warnings = append(warnings, fmt.Sprintf("%s: %s", field.NewPath("allowedTopologies").Index(i).Child("matchLabelExpressions").Index(j).Child("key"), msg)) + } + } + } + } + + return warnings +} + +func GetWarningsForCSIStorageCapacity(csc *storage.CSIStorageCapacity) []string { + if csc != nil { + return nodeapi.GetWarningsForNodeSelector(csc.NodeTopology, field.NewPath("nodeTopology")) + } + return nil +} diff --git a/pkg/api/storage/util_test.go b/pkg/api/storage/util_test.go new file mode 100644 index 00000000000..5f34570487c --- /dev/null +++ b/pkg/api/storage/util_test.go @@ -0,0 +1,171 @@ +/* +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 ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" + + "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/kubernetes/pkg/apis/storage" +) + +func TestStorageClassWarnings(t *testing.T) { + testcases := []struct { + name string + template *storage.StorageClass + expected []string + }{ + { + name: "null", + template: nil, + expected: nil, + }, + { + name: "no warning", + template: &storage.StorageClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + }, + expected: nil, + }, + { + name: "warning", + template: &storage.StorageClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + AllowedTopologies: []core.TopologySelectorTerm{ + { + MatchLabelExpressions: []core.TopologySelectorLabelRequirement{ + { + Key: "beta.kubernetes.io/arch", + Values: []string{"amd64"}, + }, + { + Key: "beta.kubernetes.io/os", + Values: []string{"linux"}, + }, + }, + }, + }, + }, + expected: []string{ + `allowedTopologies[0].matchLabelExpressions[0].key: deprecated since v1.14; use "kubernetes.io/arch" instead`, + `allowedTopologies[0].matchLabelExpressions[1].key: deprecated since v1.14; use "kubernetes.io/os" instead`, + }, + }, + } + + for _, tc := range testcases { + t.Run("podspec_"+tc.name, func(t *testing.T) { + actual := sets.NewString(GetWarningsForStorageClass(tc.template)...) + expected := sets.NewString(tc.expected...) + for _, missing := range expected.Difference(actual).List() { + t.Errorf("missing: %s", missing) + } + for _, extra := range actual.Difference(expected).List() { + t.Errorf("extra: %s", extra) + } + }) + + } +} + +func TestCSIStorageCapacityWarnings(t *testing.T) { + testcases := []struct { + name string + template *storage.CSIStorageCapacity + expected []string + }{ + { + name: "null", + template: nil, + expected: nil, + }, + { + name: "no warning", + template: &storage.CSIStorageCapacity{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + }, + expected: nil, + }, + { + name: "MatchLabels warning", + template: &storage.CSIStorageCapacity{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + NodeTopology: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/os": "linux", + }, + }, + }, + expected: []string{ + `nodeTopology.matchLabels.beta.kubernetes.io/arch: deprecated since v1.14; use "kubernetes.io/arch" instead`, + `nodeTopology.matchLabels.beta.kubernetes.io/os: deprecated since v1.14; use "kubernetes.io/os" instead`, + }, + }, + { + name: "MatchExpressions warning", + template: &storage.CSIStorageCapacity{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + NodeTopology: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "beta.kubernetes.io/arch", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"amd64"}, + }, + { + Key: "beta.kubernetes.io/os", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"linux"}, + }, + }, + }, + }, + expected: []string{ + `nodeTopology.matchExpressions[0].key: beta.kubernetes.io/arch is deprecated since v1.14; use "kubernetes.io/arch" instead`, + `nodeTopology.matchExpressions[1].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead`, + }, + }, + } + + for _, tc := range testcases { + t.Run("podspec_"+tc.name, func(t *testing.T) { + actual := sets.NewString(GetWarningsForCSIStorageCapacity(tc.template)...) + expected := sets.NewString(tc.expected...) + for _, missing := range expected.Difference(actual).List() { + t.Errorf("missing: %s", missing) + } + for _, extra := range actual.Difference(expected).List() { + t.Errorf("extra: %s", extra) + } + }) + + } +} diff --git a/pkg/registry/core/persistentvolume/strategy.go b/pkg/registry/core/persistentvolume/strategy.go index 89b5a0332fd..e175a4097ad 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(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(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..6acc70d9b30 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(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(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..559b6bba04e 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(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(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..7e833a06f4f 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" + storageutil "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 storageutil.GetWarningsForStorageClass(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 storageutil.GetWarningsForStorageClass(obj.(*storage.StorageClass)) } func (storageClassStrategy) AllowUnconditionalUpdate() bool { diff --git a/test/e2e/framework/.import-restrictions b/test/e2e/framework/.import-restrictions index 13c7be44b0f..d515c37f202 100644 --- a/test/e2e/framework/.import-restrictions +++ b/test/e2e/framework/.import-restrictions @@ -7,6 +7,7 @@ rules: - k8s.io/kubernetes/pkg/api/v1/resource - k8s.io/kubernetes/pkg/api/v1/service - k8s.io/kubernetes/pkg/api/pod + - k8s.io/kubernetes/pkg/api/node - k8s.io/kubernetes/pkg/apis/apps - k8s.io/kubernetes/pkg/apis/apps/validation - k8s.io/kubernetes/pkg/apis/autoscaling @@ -23,6 +24,7 @@ rules: - k8s.io/kubernetes/pkg/apis/core/validation - k8s.io/kubernetes/pkg/apis/extensions - k8s.io/kubernetes/pkg/apis/networking + - k8s.io/kubernetes/pkg/apis/node - k8s.io/kubernetes/pkg/apis/policy - k8s.io/kubernetes/pkg/apis/policy/validation - k8s.io/kubernetes/pkg/apis/scheduling