github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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/kubernetes.io~empty-dir/%s", dir, testPodUID, 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 t.Run(test.name, func(t *testing.T) { 312 updated, err := UpdateVolumeAnnotations(test.spec) 313 if test.expectErr { 314 if err == nil { 315 t.Fatal("Expected error, but got nil") 316 } 317 return 318 } 319 if err != nil { 320 t.Fatalf("Unexpected error: %v", err) 321 } 322 if !reflect.DeepEqual(test.expected, test.spec) { 323 t.Fatalf("Expected %+v, got %+v", test.expected, test.spec) 324 } 325 if test.expectUpdate != updated { 326 t.Errorf("Expected %v, got %v", test.expected, updated) 327 } 328 }) 329 } 330 }