sigs.k8s.io/cluster-api-provider-azure@v1.14.3/util/webhook/validator.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package webhook 18 19 import ( 20 "reflect" 21 "sort" 22 23 "k8s.io/apimachinery/pkg/util/validation/field" 24 ) 25 26 const ( 27 unsetMessage = "field is immutable, unable to set an empty value if it was already set" 28 setMessage = "field is immutable, unable to assign a value if it was already empty" 29 immutableMessage = "field is immutable" 30 ) 31 32 // ValidateImmutable validates equality across two values, 33 // and returns a meaningful error to indicate a changed value, a newly set value, or a newly unset value. 34 func ValidateImmutable(path *field.Path, oldVal, newVal any) *field.Error { 35 if reflect.TypeOf(oldVal) != reflect.TypeOf(newVal) { 36 return field.Invalid(path, newVal, "unexpected error") 37 } 38 if !reflect.ValueOf(oldVal).IsZero() { 39 // Prevent modification if it was already set to some value 40 if reflect.ValueOf(newVal).IsZero() { 41 // unsetting the field is not allowed 42 return field.Invalid(path, newVal, unsetMessage) 43 } 44 if !reflect.DeepEqual(oldVal, newVal) { 45 // changing the field is not allowed 46 return field.Invalid(path, newVal, immutableMessage) 47 } 48 } else if !reflect.ValueOf(newVal).IsZero() { 49 return field.Invalid(path, newVal, setMessage) 50 } 51 52 return nil 53 } 54 55 // ValidateZeroTransition validates equality across two values, with only exception to allow 56 // the value to transition of a zero value. 57 func ValidateZeroTransition(path *field.Path, oldVal, newVal any) *field.Error { 58 if reflect.ValueOf(newVal).IsZero() { 59 // unsetting the field is allowed 60 return nil 61 } 62 return ValidateImmutable(path, oldVal, newVal) 63 } 64 65 // EnsureStringSlicesAreEquivalent returns if two string slices have equal lengths, 66 // and that they have the exact same items; it does not enforce strict ordering of items. 67 func EnsureStringSlicesAreEquivalent(a []string, b []string) bool { 68 if len(a) != len(b) { 69 return false 70 } 71 72 sort.Strings(a) 73 sort.Strings(b) 74 75 for i := range a { 76 if a[i] != b[i] { 77 return false 78 } 79 } 80 81 return true 82 }