k8s.io/apiserver@v0.31.1/pkg/endpoints/deprecation/deprecation.go (about) 1 /* 2 Copyright 2020 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 deprecation 18 19 import ( 20 "fmt" 21 "regexp" 22 "strconv" 23 24 "k8s.io/apimachinery/pkg/runtime" 25 "k8s.io/apimachinery/pkg/runtime/schema" 26 "k8s.io/apimachinery/pkg/version" 27 ) 28 29 type apiLifecycleDeprecated interface { 30 APILifecycleDeprecated() (major, minor int) 31 } 32 33 type apiLifecycleRemoved interface { 34 APILifecycleRemoved() (major, minor int) 35 } 36 37 type apiLifecycleReplacement interface { 38 APILifecycleReplacement() schema.GroupVersionKind 39 } 40 41 // extract all digits at the beginning of the string 42 var leadingDigits = regexp.MustCompile(`^(\d+)`) 43 44 // MajorMinor parses a numeric major/minor version from the provided version info. 45 // The minor version drops all characters after the first non-digit character: 46 // 47 // version.Info{Major:"1", Minor:"2+"} -> 1,2 48 // version.Info{Major:"1", Minor:"2.3-build4"} -> 1,2 49 func MajorMinor(v version.Info) (int, int, error) { 50 major, err := strconv.Atoi(v.Major) 51 if err != nil { 52 return 0, 0, err 53 } 54 minor, err := strconv.Atoi(leadingDigits.FindString(v.Minor)) 55 if err != nil { 56 return 0, 0, err 57 } 58 return major, minor, nil 59 } 60 61 // IsDeprecated returns true if obj implements APILifecycleDeprecated() and returns 62 // a major/minor version that is non-zero and is <= the specified current major/minor version. 63 func IsDeprecated(obj runtime.Object, currentMajor, currentMinor int) bool { 64 deprecated, isDeprecated := obj.(apiLifecycleDeprecated) 65 if !isDeprecated { 66 return false 67 } 68 69 deprecatedMajor, deprecatedMinor := deprecated.APILifecycleDeprecated() 70 // no deprecation version expressed 71 if deprecatedMajor == 0 && deprecatedMinor == 0 { 72 return false 73 } 74 // no current version info available 75 if currentMajor == 0 && currentMinor == 0 { 76 return true 77 } 78 // compare deprecation version to current version 79 if deprecatedMajor > currentMajor { 80 return false 81 } 82 if deprecatedMajor == currentMajor && deprecatedMinor > currentMinor { 83 return false 84 } 85 return true 86 } 87 88 // RemovedRelease returns the major/minor version in which the given object is unavailable (in the form "<major>.<minor>") 89 // if the object implements APILifecycleRemoved() to indicate a non-zero removal version, and returns an empty string otherwise. 90 func RemovedRelease(obj runtime.Object) string { 91 if removed, hasRemovalInfo := obj.(apiLifecycleRemoved); hasRemovalInfo { 92 removedMajor, removedMinor := removed.APILifecycleRemoved() 93 if removedMajor != 0 || removedMinor != 0 { 94 return fmt.Sprintf("%d.%d", removedMajor, removedMinor) 95 } 96 } 97 return "" 98 } 99 100 // WarningMessage returns a human-readable deprecation warning if the object implements APILifecycleDeprecated() 101 // to indicate a non-zero deprecated major/minor version and has a populated GetObjectKind().GroupVersionKind(). 102 func WarningMessage(obj runtime.Object) string { 103 deprecated, isDeprecated := obj.(apiLifecycleDeprecated) 104 if !isDeprecated { 105 return "" 106 } 107 108 deprecatedMajor, deprecatedMinor := deprecated.APILifecycleDeprecated() 109 if deprecatedMajor == 0 && deprecatedMinor == 0 { 110 return "" 111 } 112 113 gvk := obj.GetObjectKind().GroupVersionKind() 114 if gvk.Empty() { 115 return "" 116 } 117 deprecationWarning := fmt.Sprintf("%s %s is deprecated in v%d.%d+", gvk.GroupVersion().String(), gvk.Kind, deprecatedMajor, deprecatedMinor) 118 119 if removed, hasRemovalInfo := obj.(apiLifecycleRemoved); hasRemovalInfo { 120 removedMajor, removedMinor := removed.APILifecycleRemoved() 121 if removedMajor != 0 || removedMinor != 0 { 122 deprecationWarning = deprecationWarning + fmt.Sprintf(", unavailable in v%d.%d+", removedMajor, removedMinor) 123 } 124 } 125 126 if replaced, hasReplacement := obj.(apiLifecycleReplacement); hasReplacement { 127 replacement := replaced.APILifecycleReplacement() 128 if !replacement.Empty() { 129 deprecationWarning = deprecationWarning + fmt.Sprintf("; use %s %s", replacement.GroupVersion().String(), replacement.Kind) 130 } 131 } 132 133 return deprecationWarning 134 }