mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Merge pull request #101688 from liggitt/field-warnings
Add field-level warning plumbing and add pod spec warnings
This commit is contained in:
commit
c115435adc
257
pkg/api/pod/warnings.go
Normal file
257
pkg/api/pod/warnings.go
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
Copyright 2021 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 pod
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/pods"
|
||||
)
|
||||
|
||||
func GetWarningsForPod(ctx context.Context, pod, oldPod *api.Pod) []string {
|
||||
if pod == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
oldSpec *api.PodSpec
|
||||
oldMeta *metav1.ObjectMeta
|
||||
)
|
||||
if oldPod != nil {
|
||||
oldSpec = &oldPod.Spec
|
||||
oldMeta = &oldPod.ObjectMeta
|
||||
}
|
||||
return warningsForPodSpecAndMeta(nil, &pod.Spec, &pod.ObjectMeta, oldSpec, oldMeta)
|
||||
}
|
||||
|
||||
func GetWarningsForPodTemplate(ctx context.Context, fieldPath *field.Path, podTemplate, oldPodTemplate *api.PodTemplateSpec) []string {
|
||||
if podTemplate == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
oldSpec *api.PodSpec
|
||||
oldMeta *metav1.ObjectMeta
|
||||
)
|
||||
if oldPodTemplate != nil {
|
||||
oldSpec = &oldPodTemplate.Spec
|
||||
oldMeta = &oldPodTemplate.ObjectMeta
|
||||
}
|
||||
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
|
||||
message string
|
||||
}{
|
||||
{
|
||||
key: `scheduler.alpha.kubernetes.io/critical-pod`,
|
||||
message: `non-functional in v1.16+; use the "priorityClassName" field instead`,
|
||||
},
|
||||
{
|
||||
key: `seccomp.security.alpha.kubernetes.io/pod`,
|
||||
prefix: `container.seccomp.security.alpha.kubernetes.io/`,
|
||||
message: `deprecated since v1.19; use the "seccompProfile" field instead`,
|
||||
},
|
||||
{
|
||||
key: `security.alpha.kubernetes.io/sysctls`,
|
||||
message: `non-functional in v1.11+; use the "sysctls" field instead`,
|
||||
},
|
||||
{
|
||||
key: `security.alpha.kubernetes.io/unsafe-sysctls`,
|
||||
message: `non-functional in v1.11+; use the "sysctls" field instead`,
|
||||
},
|
||||
}
|
||||
|
||||
func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta *metav1.ObjectMeta, oldPodSpec *api.PodSpec, oldMeta *metav1.ObjectMeta) []string {
|
||||
var warnings []string
|
||||
|
||||
// use of deprecated node labels in selectors/affinity/topology
|
||||
for k := range podSpec.NodeSelector {
|
||||
if msg, deprecated := deprecatedNodeLabels[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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, t := range podSpec.TopologySpreadConstraints {
|
||||
if msg, deprecated := deprecatedNodeLabels[t.TopologyKey]; deprecated {
|
||||
warnings = append(warnings, fmt.Sprintf(
|
||||
"%s: %s is %s",
|
||||
fieldPath.Child("spec", "topologySpreadConstraints").Index(i).Child("topologyKey"),
|
||||
t.TopologyKey,
|
||||
msg,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// use of deprecated annotations
|
||||
for _, deprecated := range deprecatedAnnotations {
|
||||
if _, exists := meta.Annotations[deprecated.key]; exists {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: %s", fieldPath.Child("metadata", "annotations").Key(deprecated.key), deprecated.message))
|
||||
}
|
||||
if len(deprecated.prefix) > 0 {
|
||||
for k := range meta.Annotations {
|
||||
if strings.HasPrefix(k, deprecated.prefix) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: %s", fieldPath.Child("metadata", "annotations").Key(k), deprecated.message))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// removed volume plugins
|
||||
for i, v := range podSpec.Volumes {
|
||||
if v.PhotonPersistentDisk != nil {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: non-functional in v1.16+", fieldPath.Child("spec", "volumes").Index(i).Child("photonPersistentDisk")))
|
||||
}
|
||||
}
|
||||
|
||||
// duplicate hostAliases (#91670, #58477)
|
||||
if len(podSpec.HostAliases) > 1 {
|
||||
items := sets.NewString()
|
||||
for i, item := range podSpec.HostAliases {
|
||||
if items.Has(item.IP) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: duplicate ip %q", fieldPath.Child("spec", "hostAliases").Index(i).Child("ip"), item.IP))
|
||||
} else {
|
||||
items.Insert(item.IP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// duplicate imagePullSecrets (#91629, #58477)
|
||||
if len(podSpec.ImagePullSecrets) > 1 {
|
||||
items := sets.NewString()
|
||||
for i, item := range podSpec.ImagePullSecrets {
|
||||
if items.Has(item.Name) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: duplicate name %q", fieldPath.Child("spec", "imagePullSecrets").Index(i).Child("name"), item.Name))
|
||||
} else {
|
||||
items.Insert(item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
// imagePullSecrets with empty name (#99454#issuecomment-787838112)
|
||||
for i, item := range podSpec.ImagePullSecrets {
|
||||
if len(item.Name) == 0 {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: invalid empty name %q", fieldPath.Child("spec", "imagePullSecrets").Index(i).Child("name"), item.Name))
|
||||
}
|
||||
}
|
||||
|
||||
// duplicate volume names (#78266, #58477)
|
||||
if len(podSpec.Volumes) > 1 {
|
||||
items := sets.NewString()
|
||||
for i, item := range podSpec.Volumes {
|
||||
if items.Has(item.Name) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: duplicate name %q", fieldPath.Child("spec", "volumes").Index(i).Child("name"), item.Name))
|
||||
} else {
|
||||
items.Insert(item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fractional memory/ephemeral-storage requests/limits (#79950, #49442, #18538)
|
||||
if value, ok := podSpec.Overhead[api.ResourceMemory]; ok && value.MilliValue()%int64(1000) != int64(0) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: fractional byte value %q is invalid, must be an integer", fieldPath.Child("spec", "overhead").Key(string(api.ResourceMemory)), value.String()))
|
||||
}
|
||||
if value, ok := podSpec.Overhead[api.ResourceEphemeralStorage]; ok && value.MilliValue()%int64(1000) != int64(0) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: fractional byte value %q is invalid, must be an integer", fieldPath.Child("spec", "overhead").Key(string(api.ResourceEphemeralStorage)), value.String()))
|
||||
}
|
||||
|
||||
pods.VisitContainersWithPath(podSpec, fieldPath.Child("spec"), func(c *api.Container, p *field.Path) bool {
|
||||
// fractional memory/ephemeral-storage requests/limits (#79950, #49442, #18538)
|
||||
if value, ok := c.Resources.Limits[api.ResourceMemory]; ok && value.MilliValue()%int64(1000) != int64(0) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: fractional byte value %q is invalid, must be an integer", p.Child("resources", "limits").Key(string(api.ResourceMemory)), value.String()))
|
||||
}
|
||||
if value, ok := c.Resources.Requests[api.ResourceMemory]; ok && value.MilliValue()%int64(1000) != int64(0) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: fractional byte value %q is invalid, must be an integer", p.Child("resources", "requests").Key(string(api.ResourceMemory)), value.String()))
|
||||
}
|
||||
if value, ok := c.Resources.Limits[api.ResourceEphemeralStorage]; ok && value.MilliValue()%int64(1000) != int64(0) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: fractional byte value %q is invalid, must be an integer", p.Child("resources", "limits").Key(string(api.ResourceEphemeralStorage)), value.String()))
|
||||
}
|
||||
if value, ok := c.Resources.Requests[api.ResourceEphemeralStorage]; ok && value.MilliValue()%int64(1000) != int64(0) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: fractional byte value %q is invalid, must be an integer", p.Child("resources", "requests").Key(string(api.ResourceEphemeralStorage)), value.String()))
|
||||
}
|
||||
|
||||
// duplicate containers[*].env (#86163, #93266, #58477)
|
||||
if len(c.Env) > 1 {
|
||||
items := sets.NewString()
|
||||
for i, item := range c.Env {
|
||||
if items.Has(item.Name) {
|
||||
warnings = append(warnings, fmt.Sprintf("%s: duplicate name %q", p.Child("env").Index(i).Child("name"), item.Name))
|
||||
} else {
|
||||
items.Insert(item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return warnings
|
||||
}
|
416
pkg/api/pod/warnings_test.go
Normal file
416
pkg/api/pod/warnings_test.go
Normal file
@ -0,0 +1,416 @@
|
||||
/*
|
||||
Copyright 2021 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 pod
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func BenchmarkNoWarnings(b *testing.B) {
|
||||
ctx := context.TODO()
|
||||
resources := api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("100m"),
|
||||
api.ResourceMemory: resource.MustParse("4M"),
|
||||
api.ResourceEphemeralStorage: resource.MustParse("4G"),
|
||||
}
|
||||
env := []api.EnvVar{
|
||||
{Name: "a"},
|
||||
{Name: "b"},
|
||||
}
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{`foo`: `bar`},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeSelector: map[string]string{"foo": "bar", "baz": "quux"},
|
||||
Affinity: &api.Affinity{
|
||||
NodeAffinity: &api.NodeAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||
NodeSelectorTerms: []api.NodeSelectorTerm{
|
||||
{MatchExpressions: []api.NodeSelectorRequirement{{Key: `foo`}}},
|
||||
},
|
||||
},
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []api.PreferredSchedulingTerm{
|
||||
{Preference: api.NodeSelectorTerm{MatchExpressions: []api.NodeSelectorRequirement{{Key: `foo`}}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologySpreadConstraints: []api.TopologySpreadConstraint{
|
||||
{TopologyKey: `foo`},
|
||||
},
|
||||
HostAliases: []api.HostAlias{
|
||||
{IP: "1.1.1.1"},
|
||||
{IP: "2.2.2.2"},
|
||||
},
|
||||
ImagePullSecrets: []api.LocalObjectReference{
|
||||
{Name: "secret1"},
|
||||
{Name: "secret2"},
|
||||
},
|
||||
InitContainers: []api.Container{
|
||||
{Name: "init1", Env: env, Resources: api.ResourceRequirements{Requests: resources, Limits: resources}},
|
||||
{Name: "init2", Env: env, Resources: api.ResourceRequirements{Requests: resources, Limits: resources}},
|
||||
},
|
||||
Containers: []api.Container{
|
||||
{Name: "container1", Env: env, Resources: api.ResourceRequirements{Requests: resources, Limits: resources}},
|
||||
{Name: "container2", Env: env, Resources: api.ResourceRequirements{Requests: resources, Limits: resources}},
|
||||
},
|
||||
Overhead: resources,
|
||||
Volumes: []api.Volume{
|
||||
{Name: "a"},
|
||||
{Name: "b"},
|
||||
},
|
||||
},
|
||||
}
|
||||
oldPod := &api.Pod{}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
w := GetWarningsForPod(ctx, pod, oldPod)
|
||||
if len(w) > 0 {
|
||||
b.Fatalf("expected 0 warnings, got %q", w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWarnings(b *testing.B) {
|
||||
ctx := context.TODO()
|
||||
resources := api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("100m"),
|
||||
api.ResourceMemory: resource.MustParse("4m"),
|
||||
api.ResourceEphemeralStorage: resource.MustParse("4m"),
|
||||
}
|
||||
env := []api.EnvVar{
|
||||
{Name: "a"},
|
||||
{Name: "a"},
|
||||
}
|
||||
pod := &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
HostAliases: []api.HostAlias{
|
||||
{IP: "1.1.1.1"},
|
||||
{IP: "1.1.1.1"},
|
||||
},
|
||||
ImagePullSecrets: []api.LocalObjectReference{
|
||||
{Name: "secret1"},
|
||||
{Name: "secret1"},
|
||||
{Name: ""},
|
||||
},
|
||||
InitContainers: []api.Container{
|
||||
{Name: "init1", Env: env, Resources: api.ResourceRequirements{Requests: resources, Limits: resources}},
|
||||
{Name: "init2", Env: env, Resources: api.ResourceRequirements{Requests: resources, Limits: resources}},
|
||||
},
|
||||
Containers: []api.Container{
|
||||
{Name: "container1", Env: env, Resources: api.ResourceRequirements{Requests: resources, Limits: resources}},
|
||||
{Name: "container2", Env: env, Resources: api.ResourceRequirements{Requests: resources, Limits: resources}},
|
||||
},
|
||||
Overhead: resources,
|
||||
Volumes: []api.Volume{
|
||||
{Name: "a"},
|
||||
{Name: "a"},
|
||||
},
|
||||
},
|
||||
}
|
||||
oldPod := &api.Pod{}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
GetWarningsForPod(ctx, pod, oldPod)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWarnings(t *testing.T) {
|
||||
resources := api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("100m"),
|
||||
api.ResourceMemory: resource.MustParse("4m"),
|
||||
api.ResourceEphemeralStorage: resource.MustParse("4m"),
|
||||
}
|
||||
testcases := []struct {
|
||||
name string
|
||||
template *api.PodTemplateSpec
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "null",
|
||||
template: nil,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "photon",
|
||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{
|
||||
{Name: "p", VolumeSource: api.VolumeSource{PhotonPersistentDisk: &api.PhotonPersistentDiskVolumeSource{}}},
|
||||
}},
|
||||
},
|
||||
expected: []string{`spec.volumes[0].photonPersistentDisk: non-functional in v1.16+`},
|
||||
},
|
||||
{
|
||||
name: "duplicate hostAlias",
|
||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||
HostAliases: []api.HostAlias{
|
||||
{IP: "1.1.1.1"},
|
||||
{IP: "1.1.1.1"},
|
||||
{IP: "1.1.1.1"},
|
||||
}},
|
||||
},
|
||||
expected: []string{
|
||||
`spec.hostAliases[1].ip: duplicate ip "1.1.1.1"`,
|
||||
`spec.hostAliases[2].ip: duplicate ip "1.1.1.1"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate imagePullSecret",
|
||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||
ImagePullSecrets: []api.LocalObjectReference{
|
||||
{Name: "a"},
|
||||
{Name: "a"},
|
||||
{Name: "a"},
|
||||
}},
|
||||
},
|
||||
expected: []string{
|
||||
`spec.imagePullSecrets[1].name: duplicate name "a"`,
|
||||
`spec.imagePullSecrets[2].name: duplicate name "a"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty imagePullSecret",
|
||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||
ImagePullSecrets: []api.LocalObjectReference{
|
||||
{Name: ""},
|
||||
}},
|
||||
},
|
||||
expected: []string{
|
||||
`spec.imagePullSecrets[0].name: invalid empty name ""`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate volume",
|
||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{
|
||||
{Name: "a"},
|
||||
{Name: "a"},
|
||||
{Name: "a"},
|
||||
}},
|
||||
},
|
||||
expected: []string{
|
||||
`spec.volumes[1].name: duplicate name "a"`,
|
||||
`spec.volumes[2].name: duplicate name "a"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate env",
|
||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{{Env: []api.EnvVar{
|
||||
{Name: "a"},
|
||||
{Name: "a"},
|
||||
{Name: "a"},
|
||||
}}},
|
||||
Containers: []api.Container{{Env: []api.EnvVar{
|
||||
{Name: "b"},
|
||||
{Name: "b"},
|
||||
{Name: "b"},
|
||||
}}},
|
||||
}},
|
||||
expected: []string{
|
||||
`spec.initContainers[0].env[1].name: duplicate name "a"`,
|
||||
`spec.initContainers[0].env[2].name: duplicate name "a"`,
|
||||
`spec.containers[0].env[1].name: duplicate name "b"`,
|
||||
`spec.containers[0].env[2].name: duplicate name "b"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fractional resources",
|
||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{{
|
||||
Resources: api.ResourceRequirements{Requests: resources, Limits: resources},
|
||||
}},
|
||||
Containers: []api.Container{{
|
||||
Resources: api.ResourceRequirements{Requests: resources, Limits: resources},
|
||||
}},
|
||||
Overhead: resources,
|
||||
}},
|
||||
expected: []string{
|
||||
`spec.initContainers[0].resources.requests[ephemeral-storage]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.initContainers[0].resources.requests[memory]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.initContainers[0].resources.limits[ephemeral-storage]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.initContainers[0].resources.limits[memory]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.containers[0].resources.requests[ephemeral-storage]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.containers[0].resources.requests[memory]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.containers[0].resources.limits[ephemeral-storage]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.containers[0].resources.limits[memory]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.overhead[ephemeral-storage]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
`spec.overhead[memory]: fractional byte value "4m" is invalid, must be an integer`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "node labels in nodeSelector",
|
||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||
NodeSelector: map[string]string{
|
||||
`beta.kubernetes.io/arch`: `true`,
|
||||
`beta.kubernetes.io/os`: `true`,
|
||||
`failure-domain.beta.kubernetes.io/region`: `true`,
|
||||
`failure-domain.beta.kubernetes.io/zone`: `true`,
|
||||
`beta.kubernetes.io/instance-type`: `true`,
|
||||
},
|
||||
}},
|
||||
expected: []string{
|
||||
`spec.nodeSelector[beta.kubernetes.io/arch]: deprecated since v1.14; use "kubernetes.io/arch" instead`,
|
||||
`spec.nodeSelector[beta.kubernetes.io/instance-type]: deprecated since v1.17; use "node.kubernetes.io/instance-type" instead`,
|
||||
`spec.nodeSelector[beta.kubernetes.io/os]: deprecated since v1.14; use "kubernetes.io/os" instead`,
|
||||
`spec.nodeSelector[failure-domain.beta.kubernetes.io/region]: deprecated since v1.17; use "topology.kubernetes.io/region" instead`,
|
||||
`spec.nodeSelector[failure-domain.beta.kubernetes.io/zone]: deprecated since v1.17; use "topology.kubernetes.io/zone" instead`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "node labels in affinity requiredDuringSchedulingIgnoredDuringExecution",
|
||||
template: &api.PodTemplateSpec{
|
||||
Spec: api.PodSpec{
|
||||
Affinity: &api.Affinity{
|
||||
NodeAffinity: &api.NodeAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||
NodeSelectorTerms: []api.NodeSelectorTerm{
|
||||
{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{
|
||||
{Key: `foo`},
|
||||
{Key: `beta.kubernetes.io/arch`},
|
||||
{Key: `beta.kubernetes.io/os`},
|
||||
{Key: `failure-domain.beta.kubernetes.io/region`},
|
||||
{Key: `failure-domain.beta.kubernetes.io/zone`},
|
||||
{Key: `beta.kubernetes.io/instance-type`},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
`spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[1].key: beta.kubernetes.io/arch is deprecated since v1.14; use "kubernetes.io/arch" instead`,
|
||||
`spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[2].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead`,
|
||||
`spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[3].key: failure-domain.beta.kubernetes.io/region is deprecated since v1.17; use "topology.kubernetes.io/region" instead`,
|
||||
`spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[4].key: failure-domain.beta.kubernetes.io/zone is deprecated since v1.17; use "topology.kubernetes.io/zone" instead`,
|
||||
`spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[5].key: beta.kubernetes.io/instance-type is deprecated since v1.17; use "node.kubernetes.io/instance-type" instead`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "node labels in affinity preferredDuringSchedulingIgnoredDuringExecution",
|
||||
template: &api.PodTemplateSpec{
|
||||
Spec: api.PodSpec{
|
||||
Affinity: &api.Affinity{
|
||||
NodeAffinity: &api.NodeAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []api.PreferredSchedulingTerm{
|
||||
{
|
||||
Preference: api.NodeSelectorTerm{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{
|
||||
{Key: `foo`},
|
||||
{Key: `beta.kubernetes.io/arch`},
|
||||
{Key: `beta.kubernetes.io/os`},
|
||||
{Key: `failure-domain.beta.kubernetes.io/region`},
|
||||
{Key: `failure-domain.beta.kubernetes.io/zone`},
|
||||
{Key: `beta.kubernetes.io/instance-type`},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
`spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].preference.matchExpressions[1].key: beta.kubernetes.io/arch is deprecated since v1.14; use "kubernetes.io/arch" instead`,
|
||||
`spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].preference.matchExpressions[2].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead`,
|
||||
`spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].preference.matchExpressions[3].key: failure-domain.beta.kubernetes.io/region is deprecated since v1.17; use "topology.kubernetes.io/region" instead`,
|
||||
`spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].preference.matchExpressions[4].key: failure-domain.beta.kubernetes.io/zone is deprecated since v1.17; use "topology.kubernetes.io/zone" instead`,
|
||||
`spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].preference.matchExpressions[5].key: beta.kubernetes.io/instance-type is deprecated since v1.17; use "node.kubernetes.io/instance-type" instead`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "node labels in topologySpreadConstraints",
|
||||
template: &api.PodTemplateSpec{
|
||||
Spec: api.PodSpec{
|
||||
TopologySpreadConstraints: []api.TopologySpreadConstraint{
|
||||
{TopologyKey: `foo`},
|
||||
{TopologyKey: `beta.kubernetes.io/arch`},
|
||||
{TopologyKey: `beta.kubernetes.io/os`},
|
||||
{TopologyKey: `failure-domain.beta.kubernetes.io/region`},
|
||||
{TopologyKey: `failure-domain.beta.kubernetes.io/zone`},
|
||||
{TopologyKey: `beta.kubernetes.io/instance-type`},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
`spec.topologySpreadConstraints[1].topologyKey: beta.kubernetes.io/arch is deprecated since v1.14; use "kubernetes.io/arch" instead`,
|
||||
`spec.topologySpreadConstraints[2].topologyKey: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead`,
|
||||
`spec.topologySpreadConstraints[3].topologyKey: failure-domain.beta.kubernetes.io/region is deprecated since v1.17; use "topology.kubernetes.io/region" instead`,
|
||||
`spec.topologySpreadConstraints[4].topologyKey: failure-domain.beta.kubernetes.io/zone is deprecated since v1.17; use "topology.kubernetes.io/zone" instead`,
|
||||
`spec.topologySpreadConstraints[5].topologyKey: beta.kubernetes.io/instance-type is deprecated since v1.17; use "node.kubernetes.io/instance-type" instead`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "annotations",
|
||||
template: &api.PodTemplateSpec{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
|
||||
`foo`: `bar`,
|
||||
`scheduler.alpha.kubernetes.io/critical-pod`: `true`,
|
||||
`seccomp.security.alpha.kubernetes.io/pod`: `default`,
|
||||
`container.seccomp.security.alpha.kubernetes.io/foo`: `default`,
|
||||
`security.alpha.kubernetes.io/sysctls`: `a,b,c`,
|
||||
`security.alpha.kubernetes.io/unsafe-sysctls`: `d,e,f`,
|
||||
}}},
|
||||
expected: []string{
|
||||
`metadata.annotations[scheduler.alpha.kubernetes.io/critical-pod]: non-functional in v1.16+; use the "priorityClassName" field instead`,
|
||||
`metadata.annotations[seccomp.security.alpha.kubernetes.io/pod]: deprecated since v1.19; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[container.seccomp.security.alpha.kubernetes.io/foo]: deprecated since v1.19; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[security.alpha.kubernetes.io/sysctls]: non-functional in v1.11+; use the "sysctls" field instead`,
|
||||
`metadata.annotations[security.alpha.kubernetes.io/unsafe-sysctls]: non-functional in v1.11+; use the "sysctls" field instead`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run("podspec_"+tc.name, func(t *testing.T) {
|
||||
actual := sets.NewString(GetWarningsForPodTemplate(context.TODO(), nil, tc.template, &api.PodTemplateSpec{})...)
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("pod_"+tc.name, func(t *testing.T) {
|
||||
var pod *api.Pod
|
||||
if tc.template != nil {
|
||||
pod = &api.Pod{
|
||||
ObjectMeta: tc.template.ObjectMeta,
|
||||
Spec: tc.template.Spec,
|
||||
}
|
||||
}
|
||||
actual := sets.NewString(GetWarningsForPod(context.TODO(), pod, &api.Pod{})...)
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -50,6 +50,11 @@ func (mutatingWebhookConfigurationStrategy) PrepareForCreate(ctx context.Context
|
||||
ic.Generation = 1
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (mutatingWebhookConfigurationStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||
func (mutatingWebhookConfigurationStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
newIC := obj.(*admissionregistration.MutatingWebhookConfiguration)
|
||||
@ -93,6 +98,11 @@ func (mutatingWebhookConfigurationStrategy) ValidateUpdate(ctx context.Context,
|
||||
return validation.ValidateMutatingWebhookConfigurationUpdate(obj.(*admissionregistration.MutatingWebhookConfiguration), old.(*admissionregistration.MutatingWebhookConfiguration), groupVersion)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (mutatingWebhookConfigurationStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for mutatingWebhookConfiguration objects. Status update should
|
||||
// only be allowed if version match.
|
||||
func (mutatingWebhookConfigurationStrategy) AllowUnconditionalUpdate() bool {
|
||||
|
@ -73,6 +73,11 @@ func (validatingWebhookConfigurationStrategy) Validate(ctx context.Context, obj
|
||||
return validation.ValidateValidatingWebhookConfiguration(obj.(*admissionregistration.ValidatingWebhookConfiguration), groupVersion)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (validatingWebhookConfigurationStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (validatingWebhookConfigurationStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -92,6 +97,11 @@ func (validatingWebhookConfigurationStrategy) ValidateUpdate(ctx context.Context
|
||||
return validation.ValidateValidatingWebhookConfigurationUpdate(obj.(*admissionregistration.ValidatingWebhookConfiguration), old.(*admissionregistration.ValidatingWebhookConfiguration), groupVersion)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (validatingWebhookConfigurationStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for validatingWebhookConfiguration objects. Status update should
|
||||
// only be allowed if version match.
|
||||
func (validatingWebhookConfigurationStrategy) AllowUnconditionalUpdate() bool {
|
||||
|
@ -73,6 +73,11 @@ func (storageVersionStrategy) Validate(ctx context.Context, obj runtime.Object)
|
||||
return validation.ValidateStorageVersion(sv)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (storageVersionStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (storageVersionStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -90,6 +95,11 @@ func (storageVersionStrategy) ValidateUpdate(ctx context.Context, obj, old runti
|
||||
return validationErrorList
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (storageVersionStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for storageVersion objects. Status update should
|
||||
// only be allowed if version match.
|
||||
func (storageVersionStrategy) AllowUnconditionalUpdate() bool {
|
||||
@ -127,3 +137,8 @@ func (storageVersionStatusStrategy) PrepareForUpdate(ctx context.Context, obj, o
|
||||
func (storageVersionStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateStorageVersionStatusUpdate(obj.(*apiserverinternal.StorageVersion), old.(*apiserverinternal.StorageVersion))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (storageVersionStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -65,6 +65,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateControllerRevision(revision)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
func (strategy) PrepareForUpdate(ctx context.Context, newObj, oldObj runtime.Object) {
|
||||
_ = oldObj.(*apps.ControllerRevision)
|
||||
_ = newObj.(*apps.ControllerRevision)
|
||||
@ -78,3 +81,6 @@ func (strategy) ValidateUpdate(ctx context.Context, newObj, oldObj runtime.Objec
|
||||
oldRevision, newRevision := oldObj.(*apps.ControllerRevision), newObj.(*apps.ControllerRevision)
|
||||
return validation.ValidateControllerRevisionUpdate(newRevision, oldRevision)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { return nil }
|
||||
|
@ -166,6 +166,12 @@ func (daemonSetStrategy) Validate(ctx context.Context, obj runtime.Object) field
|
||||
return validation.ValidateDaemonSet(daemonSet, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (daemonSetStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
newDaemonSet := obj.(*apps.DaemonSet)
|
||||
return pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newDaemonSet.Spec.Template, nil)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (daemonSetStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -203,6 +209,17 @@ func (daemonSetStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (daemonSetStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
var warnings []string
|
||||
newDaemonSet := obj.(*apps.DaemonSet)
|
||||
oldDaemonSet := old.(*apps.DaemonSet)
|
||||
if newDaemonSet.Spec.TemplateGeneration != oldDaemonSet.Spec.TemplateGeneration {
|
||||
warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newDaemonSet.Spec.Template, &oldDaemonSet.Spec.Template)
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for daemon set objects.
|
||||
func (daemonSetStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
@ -234,3 +251,8 @@ func (daemonSetStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old ru
|
||||
func (daemonSetStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateDaemonSetStatusUpdate(obj.(*apps.DaemonSet), old.(*apps.DaemonSet))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (daemonSetStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -96,6 +96,12 @@ func (deploymentStrategy) Validate(ctx context.Context, obj runtime.Object) fiel
|
||||
return validation.ValidateDeployment(deployment, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (deploymentStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
newDeployment := obj.(*apps.Deployment)
|
||||
return pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newDeployment.Spec.Template, nil)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (deploymentStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -149,6 +155,17 @@ func (deploymentStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.O
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (deploymentStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
var warnings []string
|
||||
newDeployment := obj.(*apps.Deployment)
|
||||
oldDeployment := old.(*apps.Deployment)
|
||||
if newDeployment.Generation != oldDeployment.Generation {
|
||||
warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newDeployment.Spec.Template, &oldDeployment.Spec.Template)
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
func (deploymentStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -183,3 +200,8 @@ func (deploymentStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old r
|
||||
func (deploymentStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateDeploymentStatusUpdate(obj.(*apps.Deployment), old.(*apps.Deployment))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (deploymentStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -125,6 +125,12 @@ func (rsStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorL
|
||||
return validation.ValidateReplicaSet(rs, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (rsStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
newRS := obj.(*apps.ReplicaSet)
|
||||
return pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newRS.Spec.Template, nil)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (rsStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -162,6 +168,17 @@ func (rsStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) f
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (rsStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
var warnings []string
|
||||
newReplicaSet := obj.(*apps.ReplicaSet)
|
||||
oldReplicaSet := old.(*apps.ReplicaSet)
|
||||
if newReplicaSet.Generation != oldReplicaSet.Generation {
|
||||
warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newReplicaSet.Spec.Template, &oldReplicaSet.Spec.Template)
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
func (rsStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -222,3 +239,8 @@ func (rsStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.O
|
||||
func (rsStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateReplicaSetStatusUpdate(obj.(*apps.ReplicaSet), old.(*apps.ReplicaSet))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (rsStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -113,6 +113,12 @@ func (statefulSetStrategy) Validate(ctx context.Context, obj runtime.Object) fie
|
||||
return validation.ValidateStatefulSet(statefulSet, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (statefulSetStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
newStatefulSet := obj.(*apps.StatefulSet)
|
||||
return pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newStatefulSet.Spec.Template, nil)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (statefulSetStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -133,6 +139,17 @@ func (statefulSetStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.
|
||||
return append(validationErrorList, updateErrorList...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (statefulSetStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
var warnings []string
|
||||
newStatefulSet := obj.(*apps.StatefulSet)
|
||||
oldStatefulSet := old.(*apps.StatefulSet)
|
||||
if newStatefulSet.Generation != oldStatefulSet.Generation {
|
||||
warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newStatefulSet.Spec.Template, &oldStatefulSet.Spec.Template)
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for StatefulSet objects.
|
||||
func (statefulSetStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
@ -168,3 +185,8 @@ func (statefulSetStatusStrategy) ValidateUpdate(ctx context.Context, obj, old ru
|
||||
// TODO: Validate status updates.
|
||||
return validation.ValidateStatefulSetStatusUpdate(obj.(*apps.StatefulSet), old.(*apps.StatefulSet))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (statefulSetStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -81,6 +81,11 @@ func (autoscalerStrategy) Validate(ctx context.Context, obj runtime.Object) fiel
|
||||
return validation.ValidateHorizontalPodAutoscaler(autoscaler)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (autoscalerStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (autoscalerStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -123,6 +128,11 @@ func (autoscalerStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.O
|
||||
return validation.ValidateHorizontalPodAutoscalerUpdate(obj.(*autoscaling.HorizontalPodAutoscaler), old.(*autoscaling.HorizontalPodAutoscaler))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (autoscalerStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (autoscalerStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -162,3 +172,8 @@ func (autoscalerStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old r
|
||||
func (autoscalerStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateHorizontalPodAutoscalerStatusUpdate(obj.(*autoscaling.HorizontalPodAutoscaler), old.(*autoscaling.HorizontalPodAutoscaler))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (autoscalerStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
@ -83,6 +84,8 @@ func (cronJobStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object)
|
||||
cronJob := obj.(*batch.CronJob)
|
||||
cronJob.Status = batch.CronJobStatus{}
|
||||
|
||||
cronJob.Generation = 1
|
||||
|
||||
pod.DropDisabledTemplateFields(&cronJob.Spec.JobTemplate.Spec.Template, nil)
|
||||
}
|
||||
|
||||
@ -93,6 +96,12 @@ func (cronJobStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
newCronJob.Status = oldCronJob.Status
|
||||
|
||||
pod.DropDisabledTemplateFields(&newCronJob.Spec.JobTemplate.Spec.Template, &oldCronJob.Spec.JobTemplate.Spec.Template)
|
||||
|
||||
// Any changes to the spec increment the generation number.
|
||||
// See metav1.ObjectMeta description for more information on Generation.
|
||||
if !apiequality.Semantic.DeepEqual(newCronJob.Spec, oldCronJob.Spec) {
|
||||
newCronJob.Generation = oldCronJob.Generation + 1
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates a new scheduled job.
|
||||
@ -102,6 +111,12 @@ func (cronJobStrategy) Validate(ctx context.Context, obj runtime.Object) field.E
|
||||
return validation.ValidateCronJob(cronJob, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (cronJobStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
newCronJob := obj.(*batch.CronJob)
|
||||
return pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "jobTemplate", "spec", "template"), &newCronJob.Spec.JobTemplate.Spec.Template, nil)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (cronJobStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -124,6 +139,17 @@ func (cronJobStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Obje
|
||||
return validation.ValidateCronJobUpdate(newCronJob, oldCronJob, opts)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (cronJobStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
var warnings []string
|
||||
newCronJob := obj.(*batch.CronJob)
|
||||
oldCronJob := old.(*batch.CronJob)
|
||||
if newCronJob.Generation != oldCronJob.Generation {
|
||||
warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "jobTemplate", "spec", "template"), &newCronJob.Spec.JobTemplate.Spec.Template, &oldCronJob.Spec.JobTemplate.Spec.Template)
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
type cronJobStatusStrategy struct {
|
||||
cronJobStrategy
|
||||
}
|
||||
@ -153,3 +179,8 @@ func (cronJobStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runt
|
||||
func (cronJobStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return field.ErrorList{}
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (cronJobStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -44,8 +44,9 @@ func TestCronJobStrategy(t *testing.T) {
|
||||
}
|
||||
cronJob := &batch.CronJob{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mycronjob",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Name: "mycronjob",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Generation: 999,
|
||||
},
|
||||
Spec: batch.CronJobSpec{
|
||||
Schedule: "* * * * ?",
|
||||
@ -62,11 +63,23 @@ func TestCronJobStrategy(t *testing.T) {
|
||||
if len(cronJob.Status.Active) != 0 {
|
||||
t.Errorf("CronJob does not allow setting status on create")
|
||||
}
|
||||
if cronJob.Generation != 1 {
|
||||
t.Errorf("expected Generation=1, got %d", cronJob.Generation)
|
||||
}
|
||||
errs := Strategy.Validate(ctx, cronJob)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("Unexpected error validating %v", errs)
|
||||
}
|
||||
now := metav1.Now()
|
||||
|
||||
// ensure we do not change generation for non-spec updates
|
||||
updatedLabelCronJob := cronJob.DeepCopy()
|
||||
updatedLabelCronJob.Labels = map[string]string{"a": "true"}
|
||||
Strategy.PrepareForUpdate(ctx, updatedLabelCronJob, cronJob)
|
||||
if updatedLabelCronJob.Generation != 1 {
|
||||
t.Errorf("expected Generation=1, got %d", updatedLabelCronJob.Generation)
|
||||
}
|
||||
|
||||
updatedCronJob := &batch.CronJob{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "4"},
|
||||
Spec: batch.CronJobSpec{
|
||||
@ -82,6 +95,9 @@ func TestCronJobStrategy(t *testing.T) {
|
||||
if updatedCronJob.Status.Active != nil {
|
||||
t.Errorf("PrepareForUpdate should have preserved prior version status")
|
||||
}
|
||||
if updatedCronJob.Generation != 2 {
|
||||
t.Errorf("expected Generation=2, got %d", updatedCronJob.Generation)
|
||||
}
|
||||
errs = Strategy.ValidateUpdate(ctx, updatedCronJob, cronJob)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("Expected a validation error")
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@ -89,6 +90,8 @@ func (jobStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
job := obj.(*batch.Job)
|
||||
job.Status = batch.JobStatus{}
|
||||
|
||||
job.Generation = 1
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.TTLAfterFinished) {
|
||||
job.Spec.TTLSecondsAfterFinished = nil
|
||||
}
|
||||
@ -129,6 +132,12 @@ func (jobStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object
|
||||
}
|
||||
|
||||
pod.DropDisabledTemplateFields(&newJob.Spec.Template, &oldJob.Spec.Template)
|
||||
|
||||
// Any changes to the spec increment the generation number.
|
||||
// See metav1.ObjectMeta description for more information on Generation.
|
||||
if !apiequality.Semantic.DeepEqual(newJob.Spec, oldJob.Spec) {
|
||||
newJob.Generation = oldJob.Generation + 1
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates a new job.
|
||||
@ -142,6 +151,12 @@ func (jobStrategy) Validate(ctx context.Context, obj runtime.Object) field.Error
|
||||
return validation.ValidateJob(job, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (jobStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
newJob := obj.(*batch.Job)
|
||||
return pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newJob.Spec.Template, nil)
|
||||
}
|
||||
|
||||
// generateSelector adds a selector to a job and labels to its template
|
||||
// which can be used to uniquely identify the pods created by that job,
|
||||
// if the user has requested this behavior.
|
||||
@ -216,6 +231,17 @@ func (jobStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object)
|
||||
return append(validationErrorList, updateErrorList...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (jobStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
var warnings []string
|
||||
newJob := obj.(*batch.Job)
|
||||
oldJob := old.(*batch.Job)
|
||||
if newJob.Generation != oldJob.Generation {
|
||||
warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newJob.Spec.Template, &oldJob.Spec.Template)
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
type jobStatusStrategy struct {
|
||||
jobStrategy
|
||||
}
|
||||
@ -242,6 +268,11 @@ func (jobStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
return validation.ValidateJobUpdateStatus(obj.(*batch.Job), old.(*batch.Job))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (jobStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// JobSelectableFields returns a field set that represents the object for matching purposes.
|
||||
func JobToSelectableFields(job *batch.Job) fields.Set {
|
||||
objectMetaFieldsSet := generic.ObjectMetaFieldsSet(&job.ObjectMeta, true)
|
||||
|
@ -110,6 +110,9 @@ func testJobStrategy(t *testing.T) {
|
||||
if job.Status.Active != 0 {
|
||||
t.Errorf("Job does not allow setting status on create")
|
||||
}
|
||||
if job.Generation != 1 {
|
||||
t.Errorf("expected Generation=1, got %d", job.Generation)
|
||||
}
|
||||
errs := Strategy.Validate(ctx, job)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("Unexpected error validating %v", errs)
|
||||
@ -125,6 +128,15 @@ func testJobStrategy(t *testing.T) {
|
||||
}
|
||||
|
||||
parallelism := int32(10)
|
||||
|
||||
// ensure we do not change generation for non-spec updates
|
||||
updatedLabelJob := job.DeepCopy()
|
||||
updatedLabelJob.Labels = map[string]string{"a": "true"}
|
||||
Strategy.PrepareForUpdate(ctx, updatedLabelJob, job)
|
||||
if updatedLabelJob.Generation != 1 {
|
||||
t.Errorf("expected Generation=1, got %d", updatedLabelJob.Generation)
|
||||
}
|
||||
|
||||
updatedJob := &batch.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "4"},
|
||||
Spec: batch.JobSpec{
|
||||
@ -144,6 +156,9 @@ func testJobStrategy(t *testing.T) {
|
||||
if updatedJob.Status.Active != 10 {
|
||||
t.Errorf("PrepareForUpdate should have preserved prior version status")
|
||||
}
|
||||
if updatedJob.Generation != 2 {
|
||||
t.Errorf("expected Generation=2, got %d", updatedJob.Generation)
|
||||
}
|
||||
if ttlEnabled != (updatedJob.Spec.TTLSecondsAfterFinished != nil) {
|
||||
t.Errorf("Job should only allow updating .spec.ttlSecondsAfterFinished when %v feature is enabled", features.TTLAfterFinished)
|
||||
}
|
||||
|
@ -117,6 +117,9 @@ func (csrStrategy) Validate(ctx context.Context, obj runtime.Object) field.Error
|
||||
return validation.ValidateCertificateSigningRequestCreate(csr, requestGroupVersion(ctx))
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (csrStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation (which includes a signature check).
|
||||
func (csrStrategy) Canonicalize(obj runtime.Object) {}
|
||||
|
||||
@ -127,6 +130,11 @@ func (csrStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object)
|
||||
return validation.ValidateCertificateSigningRequestUpdate(newCSR, oldCSR, requestGroupVersion(ctx))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (csrStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If AllowUnconditionalUpdate() is true and the object specified by
|
||||
// the user does not have a resource version, then generic Update()
|
||||
// populates it with the latest version. Else, it checks that the
|
||||
@ -244,6 +252,11 @@ func (csrStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
return validation.ValidateCertificateSigningRequestStatusUpdate(obj.(*certificates.CertificateSigningRequest), old.(*certificates.CertificateSigningRequest), requestGroupVersion(ctx))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (csrStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (csrStatusStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -291,6 +304,11 @@ func (csrApprovalStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.
|
||||
return validation.ValidateCertificateSigningRequestApprovalUpdate(obj.(*certificates.CertificateSigningRequest), old.(*certificates.CertificateSigningRequest), requestGroupVersion(ctx))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (csrApprovalStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
csr, ok := obj.(*certificates.CertificateSigningRequest)
|
||||
|
@ -55,6 +55,9 @@ func (leaseStrategy) Validate(ctx context.Context, obj runtime.Object) field.Err
|
||||
return validation.ValidateLease(lease)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (leaseStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (leaseStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -69,6 +72,11 @@ func (leaseStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object
|
||||
return validation.ValidateLeaseUpdate(obj.(*coordination.Lease), old.(*coordination.Lease))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (leaseStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for Lease objects.
|
||||
func (leaseStrategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
|
@ -64,6 +64,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateConfigMap(cfg)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (strategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -84,6 +87,9 @@ func (strategy) ValidateUpdate(ctx context.Context, newObj, oldObj runtime.Objec
|
||||
return validation.ValidateConfigMapUpdate(newCfg, oldCfg)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { return nil }
|
||||
|
||||
func dropDisabledFields(configMap *api.ConfigMap, oldConfigMap *api.ConfigMap) {
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,11 @@ func (endpointsStrategy) Validate(ctx context.Context, obj runtime.Object) field
|
||||
return validation.ValidateEndpointsCreate(obj.(*api.Endpoints))
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (endpointsStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (endpointsStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -69,6 +74,11 @@ func (endpointsStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
return validation.ValidateEndpointsUpdate(obj.(*api.Endpoints), old.(*api.Endpoints))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (endpointsStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (endpointsStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -64,6 +64,9 @@ func (eventStrategy) Validate(ctx context.Context, obj runtime.Object) field.Err
|
||||
return validation.ValidateEventCreate(event, groupVersion)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (eventStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (eventStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -79,6 +82,11 @@ func (eventStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object
|
||||
return validation.ValidateEventUpdate(event, oldEvent, groupVersion)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (eventStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (eventStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -56,6 +56,11 @@ func (limitrangeStrategy) Validate(ctx context.Context, obj runtime.Object) fiel
|
||||
return validation.ValidateLimitRange(limitRange)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (limitrangeStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (limitrangeStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -69,6 +74,11 @@ func (limitrangeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.O
|
||||
return validation.ValidateLimitRange(limitRange)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (limitrangeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (limitrangeStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -100,6 +100,11 @@ func (namespaceStrategy) Validate(ctx context.Context, obj runtime.Object) field
|
||||
return validation.ValidateNamespace(namespace)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (namespaceStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (namespaceStrategy) Canonicalize(obj runtime.Object) {
|
||||
// Ensure the label matches the name for namespaces just created using GenerateName,
|
||||
@ -139,6 +144,11 @@ func (namespaceStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
return append(errorList, validation.ValidateNamespaceUpdate(obj.(*api.Namespace), old.(*api.Namespace))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (namespaceStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (namespaceStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -169,6 +179,11 @@ func (namespaceStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runt
|
||||
return validation.ValidateNamespaceStatusUpdate(obj.(*api.Namespace), old.(*api.Namespace))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (namespaceStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type namespaceFinalizeStrategy struct {
|
||||
namespaceStrategy
|
||||
}
|
||||
@ -179,6 +194,11 @@ func (namespaceFinalizeStrategy) ValidateUpdate(ctx context.Context, obj, old ru
|
||||
return validation.ValidateNamespaceFinalizeUpdate(obj.(*api.Namespace), old.(*api.Namespace))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (namespaceFinalizeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (namespaceFinalizeStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
|
@ -140,6 +140,9 @@ func (nodeStrategy) Validate(ctx context.Context, obj runtime.Object) field.Erro
|
||||
return validation.ValidateNode(node)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (nodeStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (nodeStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -150,6 +153,11 @@ func (nodeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object)
|
||||
return append(errorList, validation.ValidateNodeUpdate(obj.(*api.Node), old.(*api.Node))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (nodeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nodeStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -197,6 +205,11 @@ func (nodeStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.O
|
||||
return validation.ValidateNodeUpdate(obj.(*api.Node), old.(*api.Node))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (nodeStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (nodeStatusStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
|
@ -75,6 +75,11 @@ func (persistentvolumeStrategy) Validate(ctx context.Context, obj runtime.Object
|
||||
return append(errorList, volumevalidation.ValidatePersistentVolume(persistentvolume)...)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (persistentvolumeStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (persistentvolumeStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -99,6 +104,11 @@ func (persistentvolumeStrategy) ValidateUpdate(ctx context.Context, obj, old run
|
||||
return append(errorList, validation.ValidatePersistentVolumeUpdate(newPv, old.(*api.PersistentVolume))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (persistentvolumeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (persistentvolumeStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -132,6 +142,11 @@ func (persistentvolumeStatusStrategy) ValidateUpdate(ctx context.Context, obj, o
|
||||
return validation.ValidatePersistentVolumeStatusUpdate(obj.(*api.PersistentVolume), old.(*api.PersistentVolume))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (persistentvolumeStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
persistentvolumeObj, ok := obj.(*api.PersistentVolume)
|
||||
|
@ -75,6 +75,11 @@ func (persistentvolumeclaimStrategy) Validate(ctx context.Context, obj runtime.O
|
||||
return validation.ValidatePersistentVolumeClaim(pvc)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (persistentvolumeclaimStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (persistentvolumeclaimStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -97,6 +102,11 @@ func (persistentvolumeclaimStrategy) ValidateUpdate(ctx context.Context, obj, ol
|
||||
return append(errorList, validation.ValidatePersistentVolumeClaimUpdate(obj.(*api.PersistentVolumeClaim), old.(*api.PersistentVolumeClaim))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (persistentvolumeclaimStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (persistentvolumeclaimStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -133,6 +143,11 @@ func (persistentvolumeclaimStatusStrategy) ValidateUpdate(ctx context.Context, o
|
||||
return validation.ValidatePersistentVolumeClaimStatusUpdate(obj.(*api.PersistentVolumeClaim), old.(*api.PersistentVolumeClaim))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (persistentvolumeclaimStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
persistentvolumeclaimObj, ok := obj.(*api.PersistentVolumeClaim)
|
||||
|
@ -107,6 +107,11 @@ func (podStrategy) Validate(ctx context.Context, obj runtime.Object) field.Error
|
||||
return validation.ValidatePodCreate(pod, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (podStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return podutil.GetWarningsForPod(ctx, obj.(*api.Pod), nil)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (podStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -125,6 +130,13 @@ func (podStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object)
|
||||
return validation.ValidatePodUpdate(obj.(*api.Pod), old.(*api.Pod), opts)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (podStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
// skip warnings on pod update, since humans don't typically interact directly with pods,
|
||||
// and we don't want to pay the evaluation cost on what might be a high-frequency update path
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate allows pods to be overwritten
|
||||
func (podStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
@ -198,6 +210,11 @@ func (podStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
return validation.ValidatePodStatusUpdate(obj.(*api.Pod), old.(*api.Pod), opts)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (podStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type podEphemeralContainersStrategy struct {
|
||||
podStrategy
|
||||
}
|
||||
@ -231,6 +248,11 @@ func (podEphemeralContainersStrategy) ValidateUpdate(ctx context.Context, obj, o
|
||||
return validation.ValidatePodEphemeralContainersUpdate(newPod, oldPod, opts)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (podEphemeralContainersStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
pod, ok := obj.(*api.Pod)
|
||||
|
@ -19,6 +19,7 @@ package podtemplate
|
||||
import (
|
||||
"context"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
@ -46,7 +47,7 @@ func (podTemplateStrategy) NamespaceScoped() bool {
|
||||
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
|
||||
func (podTemplateStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
template := obj.(*api.PodTemplate)
|
||||
|
||||
template.Generation = 1
|
||||
pod.DropDisabledTemplateFields(&template.Template, nil)
|
||||
}
|
||||
|
||||
@ -57,6 +58,12 @@ func (podTemplateStrategy) Validate(ctx context.Context, obj runtime.Object) fie
|
||||
return corevalidation.ValidatePodTemplate(template, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (podTemplateStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
newPodTemplate := obj.(*api.PodTemplate)
|
||||
return pod.GetWarningsForPodTemplate(ctx, field.NewPath("template"), &newPodTemplate.Template, nil)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (podTemplateStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -72,6 +79,13 @@ func (podTemplateStrategy) PrepareForUpdate(ctx context.Context, obj, old runtim
|
||||
oldTemplate := old.(*api.PodTemplate)
|
||||
|
||||
pod.DropDisabledTemplateFields(&newTemplate.Template, &oldTemplate.Template)
|
||||
|
||||
// Any changes to the template increment the generation number.
|
||||
// See metav1.ObjectMeta description for more information on Generation.
|
||||
if !apiequality.Semantic.DeepEqual(newTemplate.Template, oldTemplate.Template) {
|
||||
newTemplate.Generation = oldTemplate.Generation + 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ValidateUpdate is the default update validation for an end user.
|
||||
@ -84,6 +98,17 @@ func (podTemplateStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.
|
||||
return corevalidation.ValidatePodTemplateUpdate(template, oldTemplate, opts)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (podTemplateStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
var warnings []string
|
||||
newTemplate := obj.(*api.PodTemplate)
|
||||
oldTemplate := old.(*api.PodTemplate)
|
||||
if newTemplate.Generation != oldTemplate.Generation {
|
||||
warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("template"), &newTemplate.Template, &oldTemplate.Template)
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
func (podTemplateStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
90
pkg/registry/core/podtemplate/strategy_test.go
Normal file
90
pkg/registry/core/podtemplate/strategy_test.go
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2021 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 podtemplate
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func TestStrategy(t *testing.T) {
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
if !Strategy.NamespaceScoped() {
|
||||
t.Errorf("must be namespace scoped")
|
||||
}
|
||||
if Strategy.AllowCreateOnUpdate() {
|
||||
t.Errorf("should not allow create on update")
|
||||
}
|
||||
|
||||
podTemplate := &api.PodTemplate{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mytemplate",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Generation: 999,
|
||||
},
|
||||
Template: api.PodTemplateSpec{
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Strategy.PrepareForCreate(ctx, podTemplate)
|
||||
if podTemplate.Generation != 1 {
|
||||
t.Errorf("expected Generation=1, got %d", podTemplate.Generation)
|
||||
}
|
||||
errs := Strategy.Validate(ctx, podTemplate)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("Unexpected error validating %v", errs)
|
||||
}
|
||||
|
||||
// ensure we do not change generation for non-spec updates
|
||||
updatedLabel := podTemplate.DeepCopy()
|
||||
updatedLabel.Labels = map[string]string{"a": "true"}
|
||||
Strategy.PrepareForUpdate(ctx, updatedLabel, podTemplate)
|
||||
if updatedLabel.Generation != 1 {
|
||||
t.Errorf("expected Generation=1, got %d", updatedLabel.Generation)
|
||||
}
|
||||
|
||||
updatedTemplate := podTemplate.DeepCopy()
|
||||
updatedTemplate.ResourceVersion = "10"
|
||||
updatedTemplate.Generation = 999
|
||||
updatedTemplate.Template.Spec.RestartPolicy = api.RestartPolicyNever
|
||||
|
||||
// ensure generation is updated for spec changes
|
||||
Strategy.PrepareForUpdate(ctx, updatedTemplate, podTemplate)
|
||||
if updatedTemplate.Generation != 2 {
|
||||
t.Errorf("expected Generation=2, got %d", updatedTemplate.Generation)
|
||||
}
|
||||
errs = Strategy.ValidateUpdate(ctx, updatedTemplate, podTemplate)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("Unexpected error validating %v", errs)
|
||||
}
|
||||
|
||||
invalidUpdatedTemplate := updatedTemplate.DeepCopy()
|
||||
invalidUpdatedTemplate.Name = "changed"
|
||||
Strategy.PrepareForUpdate(ctx, invalidUpdatedTemplate, podTemplate)
|
||||
errs = Strategy.ValidateUpdate(ctx, invalidUpdatedTemplate, podTemplate)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected error validating, got none")
|
||||
}
|
||||
}
|
@ -125,6 +125,12 @@ func (rcStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorL
|
||||
return validation.ValidateReplicationController(controller, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (rcStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
newRC := obj.(*api.ReplicationController)
|
||||
return pod.GetWarningsForPodTemplate(ctx, field.NewPath("template"), newRC.Spec.Template, nil)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (rcStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -165,6 +171,17 @@ func (rcStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) f
|
||||
return errs
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (rcStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
var warnings []string
|
||||
oldRc := old.(*api.ReplicationController)
|
||||
newRc := obj.(*api.ReplicationController)
|
||||
if oldRc.Generation != newRc.Generation {
|
||||
warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), oldRc.Spec.Template, newRc.Spec.Template)
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
func (rcStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -225,3 +242,8 @@ func (rcStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.O
|
||||
func (rcStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateReplicationControllerStatusUpdate(obj.(*api.ReplicationController), old.(*api.ReplicationController))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (rcStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -77,6 +77,11 @@ func (resourcequotaStrategy) Validate(ctx context.Context, obj runtime.Object) f
|
||||
return validation.ValidateResourceQuota(resourcequota, opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (resourcequotaStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (resourcequotaStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -93,6 +98,11 @@ func (resourcequotaStrategy) ValidateUpdate(ctx context.Context, obj, old runtim
|
||||
return validation.ValidateResourceQuotaUpdate(newObj, oldObj, opts)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (resourcequotaStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourcequotaStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -126,6 +136,11 @@ func (resourcequotaStatusStrategy) ValidateUpdate(ctx context.Context, obj, old
|
||||
return validation.ValidateResourceQuotaStatusUpdate(obj.(*api.ResourceQuota), old.(*api.ResourceQuota))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (resourcequotaStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getValidationOptionsFromResourceQuota(newObj *api.ResourceQuota, oldObj *api.ResourceQuota) validation.ResourceQuotaValidationOptions {
|
||||
opts := validation.ResourceQuotaValidationOptions{
|
||||
AllowPodAffinityNamespaceSelector: utilfeature.DefaultFeatureGate.Enabled(features.PodAffinityNamespaceSelector),
|
||||
|
@ -60,6 +60,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateSecret(obj.(*api.Secret))
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
func (strategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
|
||||
@ -83,6 +86,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return validation.ValidateSecretUpdate(obj.(*api.Secret), old.(*api.Secret))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func dropDisabledFields(secret *api.Secret, oldSecret *api.Secret) {
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,9 @@ func (strategy svcStrategy) Validate(ctx context.Context, obj runtime.Object) fi
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (svcStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (svcStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -147,6 +150,11 @@ func (strategy svcStrategy) ValidateUpdate(ctx context.Context, obj, old runtime
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (svcStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svcStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
@ -302,6 +310,11 @@ func (serviceStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtim
|
||||
return validation.ValidateServiceStatusUpdate(obj.(*api.Service), old.(*api.Service))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (serviceStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NormalizeClusterIPs adjust clusterIPs based on ClusterIP. This must not
|
||||
// consider any other fields.
|
||||
func NormalizeClusterIPs(oldSvc, newSvc *api.Service) {
|
||||
|
@ -49,6 +49,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateServiceAccount(obj.(*api.ServiceAccount))
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (strategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -71,6 +74,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return validation.ValidateServiceAccountUpdate(obj.(*api.ServiceAccount), old.(*api.ServiceAccount))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (strategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -87,6 +87,11 @@ func (endpointSliceStrategy) Validate(ctx context.Context, obj runtime.Object) f
|
||||
return err
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (endpointSliceStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (endpointSliceStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -103,6 +108,11 @@ func (endpointSliceStrategy) ValidateUpdate(ctx context.Context, new, old runtim
|
||||
return validation.ValidateEndpointSliceUpdate(newEPS, oldEPS)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (endpointSliceStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for EndpointSlice objects.
|
||||
func (endpointSliceStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
|
@ -82,6 +82,11 @@ func (flowSchemaStrategy) Validate(ctx context.Context, obj runtime.Object) fiel
|
||||
return validation.ValidateFlowSchema(obj.(*flowcontrol.FlowSchema))
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (flowSchemaStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (flowSchemaStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -100,6 +105,11 @@ func (flowSchemaStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.O
|
||||
return validation.ValidateFlowSchemaUpdate(old.(*flowcontrol.FlowSchema), obj.(*flowcontrol.FlowSchema))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (flowSchemaStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type flowSchemaStatusStrategy struct {
|
||||
flowSchemaStrategy
|
||||
}
|
||||
@ -139,3 +149,8 @@ func (flowSchemaStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old r
|
||||
func (flowSchemaStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateFlowSchemaStatusUpdate(old.(*flowcontrol.FlowSchema), obj.(*flowcontrol.FlowSchema))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (flowSchemaStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -82,6 +82,11 @@ func (priorityLevelConfigurationStrategy) Validate(ctx context.Context, obj runt
|
||||
return validation.ValidatePriorityLevelConfiguration(obj.(*flowcontrol.PriorityLevelConfiguration))
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (priorityLevelConfigurationStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (priorityLevelConfigurationStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -100,6 +105,11 @@ func (priorityLevelConfigurationStrategy) ValidateUpdate(ctx context.Context, ob
|
||||
return validation.ValidatePriorityLevelConfiguration(obj.(*flowcontrol.PriorityLevelConfiguration))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (priorityLevelConfigurationStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type priorityLevelConfigurationStatusStrategy struct {
|
||||
priorityLevelConfigurationStrategy
|
||||
}
|
||||
@ -139,3 +149,8 @@ func (priorityLevelConfigurationStatusStrategy) PrepareForUpdate(ctx context.Con
|
||||
func (priorityLevelConfigurationStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidatePriorityLevelConfigurationStatusUpdate(old.(*flowcontrol.PriorityLevelConfiguration), obj.(*flowcontrol.PriorityLevelConfiguration))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (priorityLevelConfigurationStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -98,6 +98,9 @@ func (ingressStrategy) Validate(ctx context.Context, obj runtime.Object) field.E
|
||||
return validation.ValidateIngressCreate(ingress, requestGV)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (ingressStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (ingressStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -116,6 +119,11 @@ func (ingressStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Obje
|
||||
return validation.ValidateIngressUpdate(obj.(*networking.Ingress), old.(*networking.Ingress), requestGV)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (ingressStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for Ingress objects.
|
||||
func (ingressStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
@ -158,3 +166,8 @@ func (ingressStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runt
|
||||
func (ingressStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateIngressStatusUpdate(obj.(*networking.Ingress), old.(*networking.Ingress))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (ingressStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -80,6 +80,11 @@ func (ingressClassStrategy) Validate(ctx context.Context, obj runtime.Object) fi
|
||||
return validation.ValidateIngressClass(ingressClass)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (ingressClassStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (ingressClassStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -98,6 +103,11 @@ func (ingressClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime
|
||||
return validation.ValidateIngressClassUpdate(newIngressClass, oldIngressClass)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (ingressClassStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for IngressClass
|
||||
// objects.
|
||||
func (ingressClassStrategy) AllowUnconditionalUpdate() bool {
|
||||
|
@ -77,6 +77,11 @@ func (networkPolicyStrategy) Validate(ctx context.Context, obj runtime.Object) f
|
||||
return validation.ValidateNetworkPolicy(networkPolicy)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (networkPolicyStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (networkPolicyStrategy) Canonicalize(obj runtime.Object) {}
|
||||
|
||||
@ -92,6 +97,11 @@ func (networkPolicyStrategy) ValidateUpdate(ctx context.Context, obj, old runtim
|
||||
return append(validationErrorList, updateErrorList...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (networkPolicyStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for NetworkPolicy objects.
|
||||
func (networkPolicyStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
|
@ -80,6 +80,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateRuntimeClass(runtimeClass)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (strategy) Canonicalize(obj runtime.Object) {
|
||||
_ = obj.(*node.RuntimeClass)
|
||||
@ -92,6 +95,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return append(errorList, validation.ValidateRuntimeClassUpdate(newObj, old.(*node.RuntimeClass))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If AllowUnconditionalUpdate() is true and the object specified by
|
||||
// the user does not have a resource version, then generic Update()
|
||||
// populates it with the latest version. Else, it checks that the
|
||||
|
@ -90,6 +90,11 @@ func (podDisruptionBudgetStrategy) Validate(ctx context.Context, obj runtime.Obj
|
||||
return validation.ValidatePodDisruptionBudget(podDisruptionBudget)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (podDisruptionBudgetStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (podDisruptionBudgetStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -104,6 +109,11 @@ func (podDisruptionBudgetStrategy) ValidateUpdate(ctx context.Context, obj, old
|
||||
return validation.ValidatePodDisruptionBudget(obj.(*policy.PodDisruptionBudget))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (podDisruptionBudgetStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for PodDisruptionBudget objects. Status update should
|
||||
// only be allowed if version match.
|
||||
func (podDisruptionBudgetStrategy) AllowUnconditionalUpdate() bool {
|
||||
@ -152,3 +162,8 @@ func (podDisruptionBudgetStatusStrategy) ValidateUpdate(ctx context.Context, obj
|
||||
return validation.ValidatePodDisruptionBudgetStatusUpdate(obj.(*policy.PodDisruptionBudget).Status,
|
||||
old.(*policy.PodDisruptionBudget).Status, field.NewPath("status"), apiVersion)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (podDisruptionBudgetStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -81,6 +81,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidatePodSecurityPolicy(obj.(*policy.PodSecurityPolicy), opts)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
opts := validation.PodSecurityPolicyValidationOptions{
|
||||
// Allowed if the feature is enabled or the old policy already had it.
|
||||
@ -91,6 +94,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return validation.ValidatePodSecurityPolicyUpdate(old.(*policy.PodSecurityPolicy), obj.(*policy.PodSecurityPolicy), opts)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func volumeInUse(oldPSP *policy.PodSecurityPolicy, volume policy.FSType) bool {
|
||||
if oldPSP == nil {
|
||||
return false
|
||||
|
@ -74,6 +74,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateClusterRole(clusterRole)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (strategy) Canonicalize(obj runtime.Object) {
|
||||
_ = obj.(*rbac.ClusterRole)
|
||||
@ -86,6 +89,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return append(errorList, validation.ValidateClusterRoleUpdate(newObj, old.(*rbac.ClusterRole))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If AllowUnconditionalUpdate() is true and the object specified by
|
||||
// the user does not have a resource version, then generic Update()
|
||||
// populates it with the latest version. Else, it checks that the
|
||||
|
@ -74,6 +74,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateClusterRoleBinding(clusterRoleBinding)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (strategy) Canonicalize(obj runtime.Object) {
|
||||
_ = obj.(*rbac.ClusterRoleBinding)
|
||||
@ -86,6 +89,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return append(errorList, validation.ValidateClusterRoleBindingUpdate(newObj, old.(*rbac.ClusterRoleBinding))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If AllowUnconditionalUpdate() is true and the object specified by
|
||||
// the user does not have a resource version, then generic Update()
|
||||
// populates it with the latest version. Else, it checks that the
|
||||
|
@ -74,6 +74,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateRole(role)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (strategy) Canonicalize(obj runtime.Object) {
|
||||
_ = obj.(*rbac.Role)
|
||||
@ -86,6 +89,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return append(errorList, validation.ValidateRoleUpdate(newObj, old.(*rbac.Role))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If AllowUnconditionalUpdate() is true and the object specified by
|
||||
// the user does not have a resource version, then generic Update()
|
||||
// populates it with the latest version. Else, it checks that the
|
||||
|
@ -74,6 +74,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateRoleBinding(roleBinding)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (strategy) Canonicalize(obj runtime.Object) {
|
||||
_ = obj.(*rbac.RoleBinding)
|
||||
@ -86,6 +89,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return append(errorList, validation.ValidateRoleBindingUpdate(newObj, old.(*rbac.RoleBinding))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If AllowUnconditionalUpdate() is true and the object specified by
|
||||
// the user does not have a resource version, then generic Update()
|
||||
// populates it with the latest version. Else, it checks that the
|
||||
|
@ -63,6 +63,11 @@ func (priorityClassStrategy) Validate(ctx context.Context, obj runtime.Object) f
|
||||
return validation.ValidatePriorityClass(pc)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (priorityClassStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (priorityClassStrategy) Canonicalize(obj runtime.Object) {}
|
||||
|
||||
@ -76,6 +81,11 @@ func (priorityClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtim
|
||||
return validation.ValidatePriorityClassUpdate(obj.(*scheduling.PriorityClass), old.(*scheduling.PriorityClass))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (priorityClassStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for PriorityClass objects.
|
||||
func (priorityClassStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
|
@ -68,6 +68,11 @@ func (csiDriverStrategy) Validate(ctx context.Context, obj runtime.Object) field
|
||||
return validation.ValidateCSIDriver(csiDriver)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (csiDriverStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (csiDriverStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -116,6 +121,11 @@ func (csiDriverStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
return validation.ValidateCSIDriverUpdate(newCSIDriverObj, oldCSIDriverObj)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (csiDriverStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (csiDriverStrategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -59,6 +59,9 @@ func (csiNodeStrategy) Validate(ctx context.Context, obj runtime.Object) field.E
|
||||
return errs
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (csiNodeStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (csiNodeStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -90,6 +93,11 @@ func (csiNodeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Obje
|
||||
return append(errorList, validation.ValidateCSINodeUpdate(newCSINodeObj, oldCSINodeObj, validateOptions)...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (csiNodeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (csiNodeStrategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -54,6 +54,11 @@ func (csiStorageCapacityStrategy) Validate(ctx context.Context, obj runtime.Obje
|
||||
return errs
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (csiStorageCapacityStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (csiStorageCapacityStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -73,6 +78,11 @@ func (csiStorageCapacityStrategy) ValidateUpdate(ctx context.Context, obj, old r
|
||||
return append(errorList, validation.ValidateCSIStorageCapacityUpdate(newCSIStorageCapacityObj, oldCSIStorageCapacityObj)...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (csiStorageCapacityStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (csiStorageCapacityStrategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -54,6 +54,11 @@ func (storageClassStrategy) Validate(ctx context.Context, obj runtime.Object) fi
|
||||
return validation.ValidateStorageClass(storageClass)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (storageClassStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (storageClassStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -75,6 +80,11 @@ func (storageClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime
|
||||
return append(errorList, validation.ValidateStorageClassUpdate(obj.(*storage.StorageClass), old.(*storage.StorageClass))...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (storageClassStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (storageClassStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -104,6 +104,11 @@ func (volumeAttachmentStrategy) Validate(ctx context.Context, obj runtime.Object
|
||||
return errs
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (volumeAttachmentStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (volumeAttachmentStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -143,6 +148,11 @@ func (volumeAttachmentStrategy) ValidateUpdate(ctx context.Context, obj, old run
|
||||
return append(errorList, validation.ValidateVolumeAttachmentUpdate(newVolumeAttachmentObj, oldVolumeAttachmentObj)...)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (volumeAttachmentStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (volumeAttachmentStrategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -83,3 +83,8 @@ func (a statusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.O
|
||||
func (a statusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return a.customResourceStrategy.validator.ValidateStatusUpdate(ctx, obj, old, a.scale)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (statusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -161,6 +161,11 @@ func (a customResourceStrategy) Validate(ctx context.Context, obj runtime.Object
|
||||
return errs
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (customResourceStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (customResourceStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
@ -202,6 +207,11 @@ func (a customResourceStrategy) ValidateUpdate(ctx context.Context, obj, old run
|
||||
return errs
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (customResourceStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
||||
func (a customResourceStrategy) GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
|
@ -93,6 +93,11 @@ func (a customResourceValidator) ValidateUpdate(ctx context.Context, obj, old ru
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (customResourceValidator) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a customResourceValidator) ValidateStatusUpdate(ctx context.Context, obj, old runtime.Object, scale *apiextensions.CustomResourceSubresourceScale) field.ErrorList {
|
||||
u, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
|
@ -119,6 +119,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
return validation.ValidateCustomResourceDefinition(obj.(*apiextensions.CustomResourceDefinition), groupVersion)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
// AllowCreateOnUpdate is false for CustomResourceDefinition; this means a POST is
|
||||
// needed to create one.
|
||||
func (strategy) AllowCreateOnUpdate() bool {
|
||||
@ -144,6 +147,11 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
return validation.ValidateCustomResourceDefinitionUpdate(obj.(*apiextensions.CustomResourceDefinition), old.(*apiextensions.CustomResourceDefinition), groupVersion)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type statusStrategy struct {
|
||||
runtime.ObjectTyper
|
||||
names.NameGenerator
|
||||
@ -198,6 +206,11 @@ func (statusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Objec
|
||||
return validation.ValidateUpdateCustomResourceDefinitionStatus(obj.(*apiextensions.CustomResourceDefinition), old.(*apiextensions.CustomResourceDefinition))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (statusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
apiserver, ok := obj.(*apiextensions.CustomResourceDefinition)
|
||||
|
@ -115,9 +115,15 @@ func (t *testRESTStrategy) PrepareForUpdate(ctx context.Context, obj, old runtim
|
||||
func (t *testRESTStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
return nil
|
||||
}
|
||||
func (t *testRESTStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
func (t *testRESTStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return nil
|
||||
}
|
||||
func (t *testRESTStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
func (t *testRESTStrategy) Canonicalize(obj runtime.Object) {}
|
||||
|
||||
func NewTestGenericStoreRegistry(t *testing.T) (factory.DestroyFunc, *Store) {
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/apiserver/pkg/warning"
|
||||
)
|
||||
|
||||
// RESTCreateStrategy defines the minimum validation, accepted input, and
|
||||
@ -59,6 +60,26 @@ type RESTCreateStrategy interface {
|
||||
// before the object is persisted. This method should not mutate the
|
||||
// object.
|
||||
Validate(ctx context.Context, obj runtime.Object) field.ErrorList
|
||||
// WarningsOnCreate returns warnings to the client performing a create.
|
||||
// WarningsOnCreate is invoked after default fields in the object have been filled in
|
||||
// and after Validate has passed, before Canonicalize is called, and the object is persisted.
|
||||
// This method must not mutate the object.
|
||||
//
|
||||
// Be brief; limit warnings to 120 characters if possible.
|
||||
// Don't include a "Warning:" prefix in the message (that is added by clients on output).
|
||||
// Warnings returned about a specific field should be formatted as "path.to.field: message".
|
||||
// For example: `spec.imagePullSecrets[0].name: invalid empty name ""`
|
||||
//
|
||||
// Use warning messages to describe problems the client making the API request should correct or be aware of.
|
||||
// For example:
|
||||
// - use of deprecated fields/labels/annotations that will stop working in a future release
|
||||
// - use of obsolete fields/labels/annotations that are non-functional
|
||||
// - malformed or invalid specifications that prevent successful handling of the submitted object,
|
||||
// but are not rejected by validation for compatibility reasons
|
||||
//
|
||||
// Warnings should not be returned for fields which cannot be resolved by the caller.
|
||||
// For example, do not warn about spec fields in a subresource creation request.
|
||||
WarningsOnCreate(ctx context.Context, obj runtime.Object) []string
|
||||
// Canonicalize allows an object to be mutated into a canonical form. This
|
||||
// ensures that code that operates on these objects can rely on the common
|
||||
// form for things like comparison. Canonicalize is invoked after
|
||||
@ -113,6 +134,10 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx context.Context, obj runtime.
|
||||
return errors.NewInvalid(kind.GroupKind(), objectMeta.GetName(), errs)
|
||||
}
|
||||
|
||||
for _, w := range strategy.WarningsOnCreate(ctx, obj) {
|
||||
warning.AddWarning(ctx, "", w)
|
||||
}
|
||||
|
||||
strategy.Canonicalize(obj)
|
||||
|
||||
return nil
|
||||
|
@ -39,6 +39,26 @@ type RESTCreateUpdateStrategy interface {
|
||||
// filled in before the object is persisted. This method should not mutate
|
||||
// the object.
|
||||
ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList
|
||||
// WarningsOnUpdate returns warnings to the client performing the update.
|
||||
// WarningsOnUpdate is invoked after default fields in the object have been filled in
|
||||
// and after ValidateUpdate has passed, before Canonicalize is called, and before the object is persisted.
|
||||
// This method must not mutate either object.
|
||||
//
|
||||
// Be brief; limit warnings to 120 characters if possible.
|
||||
// Don't include a "Warning:" prefix in the message (that is added by clients on output).
|
||||
// Warnings returned about a specific field should be formatted as "path.to.field: message".
|
||||
// For example: `spec.imagePullSecrets[0].name: invalid empty name ""`
|
||||
//
|
||||
// Use warning messages to describe problems the client making the API request should correct or be aware of.
|
||||
// For example:
|
||||
// - use of deprecated fields/labels/annotations that will stop working in a future release
|
||||
// - use of obsolete fields/labels/annotations that are non-functional
|
||||
// - malformed or invalid specifications that prevent successful handling of the submitted object,
|
||||
// but are not rejected by validation for compatibility reasons
|
||||
//
|
||||
// Warnings should not be returned for fields which cannot be resolved by the caller.
|
||||
// For example, do not warn about spec fields in a status update.
|
||||
WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string
|
||||
// AllowUnconditionalUpdate returns true if the object can be updated
|
||||
// unconditionally (irrespective of the latest resource version), when
|
||||
// there is no resource version specified in the object.
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/apiserver/pkg/warning"
|
||||
)
|
||||
|
||||
// RESTUpdateStrategy defines the minimum validation, accepted input, and
|
||||
@ -51,6 +52,26 @@ type RESTUpdateStrategy interface {
|
||||
// filled in before the object is persisted. This method should not mutate
|
||||
// the object.
|
||||
ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList
|
||||
// WarningsOnUpdate returns warnings to the client performing the update.
|
||||
// WarningsOnUpdate is invoked after default fields in the object have been filled in
|
||||
// and after ValidateUpdate has passed, before Canonicalize is called, and before the object is persisted.
|
||||
// This method must not mutate either object.
|
||||
//
|
||||
// Be brief; limit warnings to 120 characters if possible.
|
||||
// Don't include a "Warning:" prefix in the message (that is added by clients on output).
|
||||
// Warnings returned about a specific field should be formatted as "path.to.field: message".
|
||||
// For example: `spec.imagePullSecrets[0].name: invalid empty name ""`
|
||||
//
|
||||
// Use warning messages to describe problems the client making the API request should correct or be aware of.
|
||||
// For example:
|
||||
// - use of deprecated fields/labels/annotations that will stop working in a future release
|
||||
// - use of obsolete fields/labels/annotations that are non-functional
|
||||
// - malformed or invalid specifications that prevent successful handling of the submitted object,
|
||||
// but are not rejected by validation for compatibility reasons
|
||||
//
|
||||
// Warnings should not be returned for fields which cannot be resolved by the caller.
|
||||
// For example, do not warn about spec fields in a status update.
|
||||
WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string
|
||||
// Canonicalize allows an object to be mutated into a canonical form. This
|
||||
// ensures that code that operates on these objects can rely on the common
|
||||
// form for things like comparison. Canonicalize is invoked after
|
||||
@ -144,6 +165,10 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx context.Context, obj, old run
|
||||
return errors.NewInvalid(kind.GroupKind(), objectMeta.GetName(), errs)
|
||||
}
|
||||
|
||||
for _, w := range strategy.WarningsOnUpdate(ctx, obj, old) {
|
||||
warning.AddWarning(ctx, "", w)
|
||||
}
|
||||
|
||||
strategy.Canonicalize(obj)
|
||||
|
||||
return nil
|
||||
|
@ -85,6 +85,11 @@ func (apiServerStrategy) Validate(ctx context.Context, obj runtime.Object) field
|
||||
return validation.ValidateAPIService(obj.(*apiregistration.APIService))
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (apiServerStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (apiServerStrategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
@ -100,6 +105,11 @@ func (apiServerStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Ob
|
||||
return validation.ValidateAPIServiceUpdate(obj.(*apiregistration.APIService), old.(*apiregistration.APIService))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (apiServerStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type apiServerStatusStrategy struct {
|
||||
runtime.ObjectTyper
|
||||
names.NameGenerator
|
||||
@ -156,6 +166,11 @@ func (apiServerStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runt
|
||||
return validation.ValidateAPIServiceStatusUpdate(obj.(*apiregistration.APIService), old.(*apiregistration.APIService))
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (apiServerStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAttrs returns the labels and fields of an API server for filtering purposes.
|
||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
apiserver, ok := obj.(*apiregistration.APIService)
|
||||
|
@ -79,6 +79,9 @@ func (fischerStrategy) Validate(ctx context.Context, obj runtime.Object) field.E
|
||||
return field.ErrorList{}
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (fischerStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
func (fischerStrategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
@ -93,3 +96,8 @@ func (fischerStrategy) Canonicalize(obj runtime.Object) {
|
||||
func (fischerStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return field.ErrorList{}
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (fischerStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
@ -81,6 +81,9 @@ func (flunderStrategy) Validate(ctx context.Context, obj runtime.Object) field.E
|
||||
return validation.ValidateFlunder(flunder)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
func (flunderStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
func (flunderStrategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
@ -95,3 +98,8 @@ func (flunderStrategy) Canonicalize(obj runtime.Object) {
|
||||
func (flunderStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return field.ErrorList{}
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (flunderStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user