k8s.io/kubernetes@v1.29.3/pkg/api/persistentvolume/util_test.go (about) 1 /* 2 Copyright 2018 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 persistentvolume 18 19 import ( 20 "reflect" 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/util/sets" 27 utilfeature "k8s.io/apiserver/pkg/util/feature" 28 featuregatetesting "k8s.io/component-base/featuregate/testing" 29 api "k8s.io/kubernetes/pkg/apis/core" 30 "k8s.io/kubernetes/pkg/features" 31 "k8s.io/utils/ptr" 32 ) 33 34 func TestDropDisabledFields(t *testing.T) { 35 vacName := ptr.To("vac") 36 37 tests := map[string]struct { 38 oldSpec *api.PersistentVolumeSpec 39 newSpec *api.PersistentVolumeSpec 40 expectOldSpec *api.PersistentVolumeSpec 41 expectNewSpec *api.PersistentVolumeSpec 42 vacEnabled bool 43 }{ 44 "disabled vac clears volume attributes class name": { 45 vacEnabled: false, 46 newSpec: specWithVACName(vacName), 47 expectNewSpec: specWithVACName(nil), 48 oldSpec: nil, 49 expectOldSpec: nil, 50 }, 51 "enabled vac preserve volume attributes class name": { 52 vacEnabled: true, 53 newSpec: specWithVACName(vacName), 54 expectNewSpec: specWithVACName(vacName), 55 oldSpec: nil, 56 expectOldSpec: nil, 57 }, 58 "enabled vac preserve volume attributes class name when both old and new have it": { 59 vacEnabled: true, 60 newSpec: specWithVACName(vacName), 61 expectNewSpec: specWithVACName(vacName), 62 oldSpec: specWithVACName(vacName), 63 expectOldSpec: specWithVACName(vacName), 64 }, 65 "disabled vac old pv had volume attributes class name": { 66 vacEnabled: false, 67 newSpec: specWithVACName(vacName), 68 expectNewSpec: specWithVACName(vacName), 69 oldSpec: specWithVACName(vacName), 70 expectOldSpec: specWithVACName(vacName), 71 }, 72 "enabled vac preserves volume attributes class name when old pv did not had it": { 73 vacEnabled: true, 74 newSpec: specWithVACName(vacName), 75 expectNewSpec: specWithVACName(vacName), 76 oldSpec: specWithVACName(nil), 77 expectOldSpec: specWithVACName(nil), 78 }, 79 "disabled vac neither new pv nor old pv had volume attributes class name": { 80 vacEnabled: false, 81 newSpec: specWithVACName(nil), 82 expectNewSpec: specWithVACName(nil), 83 oldSpec: specWithVACName(nil), 84 expectOldSpec: specWithVACName(nil), 85 }, 86 } 87 88 for name, tc := range tests { 89 t.Run(name, func(t *testing.T) { 90 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeAttributesClass, tc.vacEnabled)() 91 92 DropDisabledSpecFields(tc.newSpec, tc.oldSpec) 93 if !reflect.DeepEqual(tc.newSpec, tc.expectNewSpec) { 94 t.Error(cmp.Diff(tc.newSpec, tc.expectNewSpec)) 95 } 96 if !reflect.DeepEqual(tc.oldSpec, tc.expectOldSpec) { 97 t.Error(cmp.Diff(tc.oldSpec, tc.expectOldSpec)) 98 } 99 }) 100 } 101 } 102 103 func specWithVACName(vacName *string) *api.PersistentVolumeSpec { 104 pvSpec := &api.PersistentVolumeSpec{ 105 PersistentVolumeSource: api.PersistentVolumeSource{ 106 CSI: &api.CSIPersistentVolumeSource{ 107 Driver: "com.google.gcepd", 108 VolumeHandle: "foobar", 109 }, 110 }, 111 } 112 113 if vacName != nil { 114 pvSpec.VolumeAttributesClassName = vacName 115 } 116 return pvSpec 117 } 118 119 func TestWarnings(t *testing.T) { 120 testcases := []struct { 121 name string 122 template *api.PersistentVolume 123 expected []string 124 }{ 125 { 126 name: "null", 127 template: nil, 128 expected: nil, 129 }, 130 { 131 name: "no warning", 132 template: &api.PersistentVolume{ 133 ObjectMeta: metav1.ObjectMeta{ 134 Name: "foo", 135 }, 136 Status: api.PersistentVolumeStatus{ 137 Phase: api.VolumeBound, 138 }, 139 }, 140 expected: nil, 141 }, 142 { 143 name: "warning", 144 template: &api.PersistentVolume{ 145 ObjectMeta: metav1.ObjectMeta{ 146 Name: "foo", 147 Annotations: map[string]string{ 148 api.BetaStorageClassAnnotation: "", 149 }, 150 }, 151 Spec: api.PersistentVolumeSpec{ 152 NodeAffinity: &api.VolumeNodeAffinity{ 153 Required: &api.NodeSelector{ 154 NodeSelectorTerms: []api.NodeSelectorTerm{ 155 { 156 MatchExpressions: []api.NodeSelectorRequirement{ 157 { 158 Key: "beta.kubernetes.io/os", 159 Operator: "Equal", 160 Values: []string{"windows"}, 161 }, 162 }, 163 }, 164 }, 165 }, 166 }, 167 }, 168 Status: api.PersistentVolumeStatus{ 169 Phase: api.VolumeBound, 170 }, 171 }, 172 expected: []string{ 173 `metadata.annotations[volume.beta.kubernetes.io/storage-class]: deprecated since v1.8; use "storageClassName" attribute instead`, 174 `spec.nodeAffinity.required.nodeSelectorTerms[0].matchExpressions[0].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead`, 175 }, 176 }, 177 { 178 name: "PV CephFS deprecation warning", 179 template: &api.PersistentVolume{ 180 Spec: api.PersistentVolumeSpec{ 181 PersistentVolumeSource: api.PersistentVolumeSource{ 182 CephFS: &api.CephFSPersistentVolumeSource{ 183 Monitors: nil, 184 Path: "", 185 User: "", 186 SecretFile: "", 187 SecretRef: nil, 188 ReadOnly: false, 189 }, 190 }, 191 }, 192 }, 193 expected: []string{ 194 `spec.cephfs: deprecated in v1.28, non-functional in v1.31+`, 195 }, 196 }, 197 { 198 name: "PV PhotonPersistentDisk deprecation warning", 199 template: &api.PersistentVolume{ 200 Spec: api.PersistentVolumeSpec{ 201 PersistentVolumeSource: api.PersistentVolumeSource{ 202 PhotonPersistentDisk: &api.PhotonPersistentDiskVolumeSource{ 203 PdID: "", 204 FSType: "", 205 }, 206 }, 207 }, 208 }, 209 expected: []string{ 210 `spec.photonPersistentDisk: deprecated in v1.11, non-functional in v1.16+`, 211 }, 212 }, 213 { 214 name: "PV RBD deprecation warning", 215 template: &api.PersistentVolume{ 216 Spec: api.PersistentVolumeSpec{ 217 PersistentVolumeSource: api.PersistentVolumeSource{ 218 RBD: &api.RBDPersistentVolumeSource{ 219 CephMonitors: nil, 220 RBDImage: "", 221 FSType: "", 222 RBDPool: "", 223 RadosUser: "", 224 Keyring: "", 225 SecretRef: nil, 226 ReadOnly: false, 227 }, 228 }, 229 }, 230 }, 231 expected: []string{ 232 `spec.rbd: deprecated in v1.28, non-functional in v1.31+`}, 233 }, 234 { 235 name: "PV ScaleIO deprecation warning", 236 template: &api.PersistentVolume{ 237 Spec: api.PersistentVolumeSpec{ 238 PersistentVolumeSource: api.PersistentVolumeSource{ 239 ScaleIO: &api.ScaleIOPersistentVolumeSource{ 240 Gateway: "", 241 System: "", 242 SecretRef: nil, 243 SSLEnabled: false, 244 ProtectionDomain: "", 245 StoragePool: "", 246 StorageMode: "", 247 VolumeName: "", 248 FSType: "", 249 ReadOnly: false, 250 }, 251 }, 252 }, 253 }, 254 expected: []string{ 255 `spec.scaleIO: deprecated in v1.16, non-functional in v1.22+`, 256 }, 257 }, 258 { 259 name: "PV StorageOS deprecation warning", 260 template: &api.PersistentVolume{ 261 Spec: api.PersistentVolumeSpec{ 262 PersistentVolumeSource: api.PersistentVolumeSource{ 263 StorageOS: &api.StorageOSPersistentVolumeSource{ 264 VolumeName: "", 265 VolumeNamespace: "", 266 FSType: "", 267 ReadOnly: false, 268 SecretRef: nil, 269 }, 270 }, 271 }, 272 }, 273 expected: []string{ 274 `spec.storageOS: deprecated in v1.22, non-functional in v1.25+`, 275 }, 276 }, 277 { 278 name: "PV GlusterFS deprecation warning", 279 template: &api.PersistentVolume{ 280 Spec: api.PersistentVolumeSpec{ 281 PersistentVolumeSource: api.PersistentVolumeSource{ 282 Glusterfs: &api.GlusterfsPersistentVolumeSource{ 283 EndpointsName: "", 284 Path: "", 285 ReadOnly: false, 286 EndpointsNamespace: nil, 287 }, 288 }, 289 }, 290 }, 291 expected: []string{ 292 `spec.glusterfs: deprecated in v1.25, non-functional in v1.26+`, 293 }, 294 }, 295 } 296 297 for _, tc := range testcases { 298 t.Run("podspec_"+tc.name, func(t *testing.T) { 299 actual := sets.NewString(GetWarningsForPersistentVolume(tc.template)...) 300 expected := sets.NewString(tc.expected...) 301 for _, missing := range expected.Difference(actual).List() { 302 t.Errorf("missing: %s", missing) 303 } 304 for _, extra := range actual.Difference(expected).List() { 305 t.Errorf("extra: %s", extra) 306 } 307 }) 308 309 } 310 }