gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/shim/utils/volumes_test.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package utils 16 17 import ( 18 "fmt" 19 "io/ioutil" 20 "os" 21 "reflect" 22 "testing" 23 24 specs "github.com/opencontainers/runtime-spec/specs-go" 25 ) 26 27 func TestUpdateVolumeAnnotations(t *testing.T) { 28 dir, err := ioutil.TempDir("", "test-update-volume-annotations") 29 if err != nil { 30 t.Fatalf("create tempdir: %v", err) 31 } 32 defer os.RemoveAll(dir) 33 kubeletPodsDir = dir 34 35 const ( 36 testPodUID = "testuid" 37 testVolumeName = "testvolume" 38 testLogDirPath = "/var/log/pods/testns_testname_" + testPodUID 39 testLegacyLogDirPath = "/var/log/pods/" + testPodUID 40 ) 41 testVolumePath := fmt.Sprintf("%s/%s/volumes/%s/%s", dir, testPodUID, emptyDirVolumesDir, testVolumeName) 42 43 if err := os.MkdirAll(testVolumePath, 0755); err != nil { 44 t.Fatalf("Create test volume: %v", err) 45 } 46 47 for _, test := range []struct { 48 name string 49 spec *specs.Spec 50 expected *specs.Spec 51 expectErr bool 52 expectUpdate bool 53 }{ 54 { 55 name: "volume annotations for sandbox", 56 spec: &specs.Spec{ 57 Annotations: map[string]string{ 58 sandboxLogDirAnnotation: testLogDirPath, 59 ContainerTypeAnnotation: containerTypeSandbox, 60 volumeKeyPrefix + testVolumeName + ".share": "pod", 61 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 62 volumeKeyPrefix + testVolumeName + ".options": "ro", 63 }, 64 }, 65 expected: &specs.Spec{ 66 Annotations: map[string]string{ 67 sandboxLogDirAnnotation: testLogDirPath, 68 ContainerTypeAnnotation: containerTypeSandbox, 69 volumeKeyPrefix + testVolumeName + ".share": "pod", 70 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 71 volumeKeyPrefix + testVolumeName + ".options": "ro", 72 volumeKeyPrefix + testVolumeName + ".source": testVolumePath, 73 }, 74 }, 75 expectUpdate: true, 76 }, 77 { 78 name: "volume annotations for sandbox with legacy log path", 79 spec: &specs.Spec{ 80 Annotations: map[string]string{ 81 sandboxLogDirAnnotation: testLegacyLogDirPath, 82 ContainerTypeAnnotation: containerTypeSandbox, 83 volumeKeyPrefix + testVolumeName + ".share": "pod", 84 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 85 volumeKeyPrefix + testVolumeName + ".options": "ro", 86 }, 87 }, 88 expected: &specs.Spec{ 89 Annotations: map[string]string{ 90 sandboxLogDirAnnotation: testLegacyLogDirPath, 91 ContainerTypeAnnotation: containerTypeSandbox, 92 volumeKeyPrefix + testVolumeName + ".share": "pod", 93 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 94 volumeKeyPrefix + testVolumeName + ".options": "ro", 95 volumeKeyPrefix + testVolumeName + ".source": testVolumePath, 96 }, 97 }, 98 expectUpdate: true, 99 }, 100 { 101 name: "tmpfs: volume annotations for container", 102 spec: &specs.Spec{ 103 Mounts: []specs.Mount{ 104 { 105 Destination: "/test", 106 Type: "bind", 107 Source: testVolumePath, 108 Options: []string{"ro"}, 109 }, 110 { 111 Destination: "/random", 112 Type: "bind", 113 Source: "/random", 114 Options: []string{"ro"}, 115 }, 116 }, 117 Annotations: map[string]string{ 118 ContainerTypeAnnotation: ContainerTypeContainer, 119 volumeKeyPrefix + testVolumeName + ".share": "pod", 120 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 121 volumeKeyPrefix + testVolumeName + ".options": "ro", 122 }, 123 }, 124 expected: &specs.Spec{ 125 Mounts: []specs.Mount{ 126 { 127 Destination: "/test", 128 Type: "tmpfs", 129 Source: testVolumePath, 130 Options: []string{"ro"}, 131 }, 132 { 133 Destination: "/random", 134 Type: "bind", 135 Source: "/random", 136 Options: []string{"ro"}, 137 }, 138 }, 139 Annotations: map[string]string{ 140 ContainerTypeAnnotation: ContainerTypeContainer, 141 volumeKeyPrefix + testVolumeName + ".share": "pod", 142 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 143 volumeKeyPrefix + testVolumeName + ".options": "ro", 144 }, 145 }, 146 expectUpdate: true, 147 }, 148 { 149 name: "bind: volume annotations for container", 150 spec: &specs.Spec{ 151 Mounts: []specs.Mount{ 152 { 153 Destination: "/test", 154 Type: "bind", 155 Source: testVolumePath, 156 Options: []string{"ro"}, 157 }, 158 }, 159 Annotations: map[string]string{ 160 ContainerTypeAnnotation: ContainerTypeContainer, 161 volumeKeyPrefix + testVolumeName + ".share": "container", 162 volumeKeyPrefix + testVolumeName + ".type": "bind", 163 volumeKeyPrefix + testVolumeName + ".options": "ro", 164 }, 165 }, 166 expected: &specs.Spec{ 167 Mounts: []specs.Mount{ 168 { 169 Destination: "/test", 170 Type: "bind", 171 Source: testVolumePath, 172 Options: []string{"ro"}, 173 }, 174 }, 175 Annotations: map[string]string{ 176 ContainerTypeAnnotation: ContainerTypeContainer, 177 volumeKeyPrefix + testVolumeName + ".share": "container", 178 volumeKeyPrefix + testVolumeName + ".type": "bind", 179 volumeKeyPrefix + testVolumeName + ".options": "ro", 180 }, 181 }, 182 expectUpdate: true, 183 }, 184 { 185 name: "should not return error without pod log directory", 186 spec: &specs.Spec{ 187 Annotations: map[string]string{ 188 ContainerTypeAnnotation: containerTypeSandbox, 189 volumeKeyPrefix + testVolumeName + ".share": "pod", 190 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 191 volumeKeyPrefix + testVolumeName + ".options": "ro", 192 }, 193 }, 194 expected: &specs.Spec{ 195 Annotations: map[string]string{ 196 ContainerTypeAnnotation: containerTypeSandbox, 197 volumeKeyPrefix + testVolumeName + ".share": "pod", 198 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 199 volumeKeyPrefix + testVolumeName + ".options": "ro", 200 }, 201 }, 202 }, 203 { 204 name: "should return error if volume path does not exist", 205 spec: &specs.Spec{ 206 Annotations: map[string]string{ 207 sandboxLogDirAnnotation: testLogDirPath, 208 ContainerTypeAnnotation: containerTypeSandbox, 209 volumeKeyPrefix + "notexist.share": "pod", 210 volumeKeyPrefix + "notexist.type": "tmpfs", 211 volumeKeyPrefix + "notexist.options": "ro", 212 }, 213 }, 214 expectErr: true, 215 }, 216 { 217 name: "no volume annotations for sandbox", 218 spec: &specs.Spec{ 219 Annotations: map[string]string{ 220 sandboxLogDirAnnotation: testLogDirPath, 221 ContainerTypeAnnotation: containerTypeSandbox, 222 }, 223 }, 224 expected: &specs.Spec{ 225 Annotations: map[string]string{ 226 sandboxLogDirAnnotation: testLogDirPath, 227 ContainerTypeAnnotation: containerTypeSandbox, 228 }, 229 }, 230 }, 231 { 232 name: "no volume annotations for container", 233 spec: &specs.Spec{ 234 Mounts: []specs.Mount{ 235 { 236 Destination: "/test", 237 Type: "bind", 238 Source: "/test", 239 Options: []string{"ro"}, 240 }, 241 { 242 Destination: "/random", 243 Type: "bind", 244 Source: "/random", 245 Options: []string{"ro"}, 246 }, 247 }, 248 Annotations: map[string]string{ 249 ContainerTypeAnnotation: ContainerTypeContainer, 250 }, 251 }, 252 expected: &specs.Spec{ 253 Mounts: []specs.Mount{ 254 { 255 Destination: "/test", 256 Type: "bind", 257 Source: "/test", 258 Options: []string{"ro"}, 259 }, 260 { 261 Destination: "/random", 262 Type: "bind", 263 Source: "/random", 264 Options: []string{"ro"}, 265 }, 266 }, 267 Annotations: map[string]string{ 268 ContainerTypeAnnotation: ContainerTypeContainer, 269 }, 270 }, 271 }, 272 { 273 name: "bind options removed", 274 spec: &specs.Spec{ 275 Annotations: map[string]string{ 276 ContainerTypeAnnotation: ContainerTypeContainer, 277 volumeKeyPrefix + testVolumeName + ".share": "pod", 278 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 279 volumeKeyPrefix + testVolumeName + ".options": "ro", 280 volumeKeyPrefix + testVolumeName + ".source": testVolumePath, 281 }, 282 Mounts: []specs.Mount{ 283 { 284 Destination: "/dst", 285 Type: "bind", 286 Source: testVolumePath, 287 Options: []string{"ro", "bind", "rbind"}, 288 }, 289 }, 290 }, 291 expected: &specs.Spec{ 292 Annotations: map[string]string{ 293 ContainerTypeAnnotation: ContainerTypeContainer, 294 volumeKeyPrefix + testVolumeName + ".share": "pod", 295 volumeKeyPrefix + testVolumeName + ".type": "tmpfs", 296 volumeKeyPrefix + testVolumeName + ".options": "ro", 297 volumeKeyPrefix + testVolumeName + ".source": testVolumePath, 298 }, 299 Mounts: []specs.Mount{ 300 { 301 Destination: "/dst", 302 Type: "tmpfs", 303 Source: testVolumePath, 304 Options: []string{"ro"}, 305 }, 306 }, 307 }, 308 expectUpdate: true, 309 }, 310 { 311 name: "shm-sandbox", 312 spec: &specs.Spec{ 313 Annotations: map[string]string{ 314 sandboxLogDirAnnotation: testLogDirPath, 315 ContainerTypeAnnotation: containerTypeSandbox, 316 }, 317 Mounts: []specs.Mount{ 318 { 319 Destination: "/dev/shm", 320 Type: "bind", 321 Source: testVolumePath, 322 Options: []string{"ro", "foo"}, 323 }, 324 }, 325 }, 326 expected: &specs.Spec{ 327 Annotations: map[string]string{ 328 sandboxLogDirAnnotation: testLogDirPath, 329 ContainerTypeAnnotation: containerTypeSandbox, 330 volumeKeyPrefix + devshmName + ".share": "pod", 331 volumeKeyPrefix + devshmName + ".type": "tmpfs", 332 volumeKeyPrefix + devshmName + ".options": "rw", 333 volumeKeyPrefix + devshmName + ".source": testVolumePath, 334 }, 335 Mounts: []specs.Mount{ 336 { 337 Destination: "/dev/shm", 338 Type: "tmpfs", 339 Source: testVolumePath, 340 Options: []string{"ro", "foo"}, 341 }, 342 }, 343 }, 344 expectUpdate: true, 345 }, 346 { 347 name: "shm-container", 348 spec: &specs.Spec{ 349 Annotations: map[string]string{ 350 ContainerTypeAnnotation: ContainerTypeContainer, 351 }, 352 Mounts: []specs.Mount{ 353 { 354 Destination: "/dev/shm", 355 Type: "bind", 356 Source: testVolumePath, 357 Options: []string{"ro", "foo"}, 358 }, 359 }, 360 }, 361 expected: &specs.Spec{ 362 Annotations: map[string]string{ 363 ContainerTypeAnnotation: ContainerTypeContainer, 364 }, 365 Mounts: []specs.Mount{ 366 { 367 Destination: "/dev/shm", 368 Type: "tmpfs", 369 Source: testVolumePath, 370 Options: []string{"ro", "foo"}, 371 }, 372 }, 373 }, 374 expectUpdate: true, 375 }, 376 { 377 name: "shm-duplicate", 378 spec: &specs.Spec{ 379 Annotations: map[string]string{ 380 ContainerTypeAnnotation: ContainerTypeContainer, 381 }, 382 Mounts: []specs.Mount{ 383 { 384 Destination: "/dev/shm", 385 Type: "bind", 386 Source: testVolumePath, 387 Options: []string{"ro", "foo"}, 388 }, 389 { 390 Destination: "/dev/shm", 391 Type: "tmpfs", 392 }, 393 { 394 Destination: "/home", 395 Type: "bind", 396 Source: "/another/mount", 397 Options: []string{"rw"}, 398 }, 399 }, 400 }, 401 expected: &specs.Spec{ 402 Annotations: map[string]string{ 403 ContainerTypeAnnotation: ContainerTypeContainer, 404 }, 405 Mounts: []specs.Mount{ 406 { 407 Destination: "/dev/shm", 408 Type: "tmpfs", 409 Source: testVolumePath, 410 Options: []string{"ro", "foo"}, 411 }, 412 { 413 Destination: "/home", 414 Type: "bind", 415 Source: "/another/mount", 416 Options: []string{"rw"}, 417 }, 418 }, 419 }, 420 expectUpdate: true, 421 }, 422 } { 423 t.Run(test.name, func(t *testing.T) { 424 updated, err := UpdateVolumeAnnotations(test.spec) 425 if test.expectErr { 426 if err == nil { 427 t.Fatal("UpdateVolumeAnnotations(spec): nil, want: error") 428 } 429 return 430 } 431 if err != nil { 432 t.Fatalf("UpdateVolumeAnnotations(spec): %v", err) 433 } 434 if test.expectUpdate != updated { 435 t.Errorf("want: %v, got: %v", test.expectUpdate, updated) 436 } 437 if !reflect.DeepEqual(test.expected, test.spec) { 438 t.Fatalf("want: %+v, got: %+v", test.expected, test.spec) 439 } 440 }) 441 } 442 }