1
16
17 package projected
18
19 import (
20 "crypto/ed25519"
21 "crypto/rand"
22 "crypto/x509"
23 "crypto/x509/pkix"
24 "encoding/pem"
25 "fmt"
26 "math/big"
27 "os"
28 "path/filepath"
29 "reflect"
30 "strings"
31 "testing"
32
33 "github.com/google/go-cmp/cmp"
34 authenticationv1 "k8s.io/api/authentication/v1"
35 certificatesv1alpha1 "k8s.io/api/certificates/v1alpha1"
36 v1 "k8s.io/api/core/v1"
37 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38 "k8s.io/apimachinery/pkg/runtime"
39 "k8s.io/apimachinery/pkg/types"
40 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
41 clientset "k8s.io/client-go/kubernetes"
42 "k8s.io/client-go/kubernetes/fake"
43 clitesting "k8s.io/client-go/testing"
44 pkgauthenticationv1 "k8s.io/kubernetes/pkg/apis/authentication/v1"
45 pkgcorev1 "k8s.io/kubernetes/pkg/apis/core/v1"
46 "k8s.io/kubernetes/pkg/volume"
47 "k8s.io/kubernetes/pkg/volume/emptydir"
48 volumetest "k8s.io/kubernetes/pkg/volume/testing"
49 "k8s.io/kubernetes/pkg/volume/util"
50 utilptr "k8s.io/utils/pointer"
51 )
52
53 func TestCollectDataWithSecret(t *testing.T) {
54 caseMappingMode := int32(0400)
55 cases := []struct {
56 name string
57 mappings []v1.KeyToPath
58 secret *v1.Secret
59 mode int32
60 optional bool
61 payload map[string]util.FileProjection
62 success bool
63 }{
64 {
65 name: "no overrides",
66 secret: &v1.Secret{
67 Data: map[string][]byte{
68 "foo": []byte("foo"),
69 "bar": []byte("bar"),
70 },
71 },
72 mode: 0644,
73 payload: map[string]util.FileProjection{
74 "foo": {Data: []byte("foo"), Mode: 0644},
75 "bar": {Data: []byte("bar"), Mode: 0644},
76 },
77 success: true,
78 },
79 {
80 name: "basic 1",
81 mappings: []v1.KeyToPath{
82 {
83 Key: "foo",
84 Path: "path/to/foo.txt",
85 },
86 },
87 secret: &v1.Secret{
88 Data: map[string][]byte{
89 "foo": []byte("foo"),
90 "bar": []byte("bar"),
91 },
92 },
93 mode: 0644,
94 payload: map[string]util.FileProjection{
95 "path/to/foo.txt": {Data: []byte("foo"), Mode: 0644},
96 },
97 success: true,
98 },
99 {
100 name: "subdirs",
101 mappings: []v1.KeyToPath{
102 {
103 Key: "foo",
104 Path: "path/to/1/2/3/foo.txt",
105 },
106 },
107 secret: &v1.Secret{
108 Data: map[string][]byte{
109 "foo": []byte("foo"),
110 "bar": []byte("bar"),
111 },
112 },
113 mode: 0644,
114 payload: map[string]util.FileProjection{
115 "path/to/1/2/3/foo.txt": {Data: []byte("foo"), Mode: 0644},
116 },
117 success: true,
118 },
119 {
120 name: "subdirs 2",
121 mappings: []v1.KeyToPath{
122 {
123 Key: "foo",
124 Path: "path/to/1/2/3/foo.txt",
125 },
126 },
127 secret: &v1.Secret{
128 Data: map[string][]byte{
129 "foo": []byte("foo"),
130 "bar": []byte("bar"),
131 },
132 },
133 mode: 0644,
134 payload: map[string]util.FileProjection{
135 "path/to/1/2/3/foo.txt": {Data: []byte("foo"), Mode: 0644},
136 },
137 success: true,
138 },
139 {
140 name: "subdirs 3",
141 mappings: []v1.KeyToPath{
142 {
143 Key: "foo",
144 Path: "path/to/1/2/3/foo.txt",
145 },
146 {
147 Key: "bar",
148 Path: "another/path/to/the/esteemed/bar.bin",
149 },
150 },
151 secret: &v1.Secret{
152 Data: map[string][]byte{
153 "foo": []byte("foo"),
154 "bar": []byte("bar"),
155 },
156 },
157 mode: 0644,
158 payload: map[string]util.FileProjection{
159 "path/to/1/2/3/foo.txt": {Data: []byte("foo"), Mode: 0644},
160 "another/path/to/the/esteemed/bar.bin": {Data: []byte("bar"), Mode: 0644},
161 },
162 success: true,
163 },
164 {
165 name: "non existent key",
166 mappings: []v1.KeyToPath{
167 {
168 Key: "zab",
169 Path: "path/to/foo.txt",
170 },
171 },
172 secret: &v1.Secret{
173 Data: map[string][]byte{
174 "foo": []byte("foo"),
175 "bar": []byte("bar"),
176 },
177 },
178 mode: 0644,
179 success: false,
180 },
181 {
182 name: "mapping with Mode",
183 mappings: []v1.KeyToPath{
184 {
185 Key: "foo",
186 Path: "foo.txt",
187 Mode: &caseMappingMode,
188 },
189 {
190 Key: "bar",
191 Path: "bar.bin",
192 Mode: &caseMappingMode,
193 },
194 },
195 secret: &v1.Secret{
196 Data: map[string][]byte{
197 "foo": []byte("foo"),
198 "bar": []byte("bar"),
199 },
200 },
201 mode: 0644,
202 payload: map[string]util.FileProjection{
203 "foo.txt": {Data: []byte("foo"), Mode: caseMappingMode},
204 "bar.bin": {Data: []byte("bar"), Mode: caseMappingMode},
205 },
206 success: true,
207 },
208 {
209 name: "mapping with defaultMode",
210 mappings: []v1.KeyToPath{
211 {
212 Key: "foo",
213 Path: "foo.txt",
214 },
215 {
216 Key: "bar",
217 Path: "bar.bin",
218 },
219 },
220 secret: &v1.Secret{
221 Data: map[string][]byte{
222 "foo": []byte("foo"),
223 "bar": []byte("bar"),
224 },
225 },
226 mode: 0644,
227 payload: map[string]util.FileProjection{
228 "foo.txt": {Data: []byte("foo"), Mode: 0644},
229 "bar.bin": {Data: []byte("bar"), Mode: 0644},
230 },
231 success: true,
232 },
233 {
234 name: "optional non existent key",
235 mappings: []v1.KeyToPath{
236 {
237 Key: "zab",
238 Path: "path/to/foo.txt",
239 },
240 },
241 secret: &v1.Secret{
242 Data: map[string][]byte{
243 "foo": []byte("foo"),
244 "bar": []byte("bar"),
245 },
246 },
247 mode: 0644,
248 optional: true,
249 payload: map[string]util.FileProjection{},
250 success: true,
251 },
252 }
253
254 for _, tc := range cases {
255 t.Run(tc.name, func(t *testing.T) {
256
257 testNamespace := "test_projected_namespace"
258 tc.secret.ObjectMeta = metav1.ObjectMeta{
259 Namespace: testNamespace,
260 Name: tc.name,
261 }
262
263 source := makeProjection(tc.name, utilptr.Int32Ptr(tc.mode), "secret")
264 source.Sources[0].Secret.Items = tc.mappings
265 source.Sources[0].Secret.Optional = &tc.optional
266
267 testPodUID := types.UID("test_pod_uid")
268 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
269 client := fake.NewSimpleClientset(tc.secret)
270 tempDir, host := newTestHost(t, client)
271 defer os.RemoveAll(tempDir)
272 var myVolumeMounter = projectedVolumeMounter{
273 projectedVolume: &projectedVolume{
274 sources: source.Sources,
275 podUID: pod.UID,
276 plugin: &projectedPlugin{
277 host: host,
278 getSecret: host.GetSecretFunc(),
279 },
280 },
281 source: *source,
282 pod: pod,
283 }
284
285 actualPayload, err := myVolumeMounter.collectData(volume.MounterArgs{})
286 if err != nil && tc.success {
287 t.Errorf("%v: unexpected failure making payload: %v", tc.name, err)
288 return
289 }
290 if err == nil && !tc.success {
291 t.Errorf("%v: unexpected success making payload", tc.name)
292 return
293 }
294 if !tc.success {
295 return
296 }
297 if e, a := tc.payload, actualPayload; !reflect.DeepEqual(e, a) {
298 t.Errorf("%v: expected and actual payload do not match", tc.name)
299 }
300 })
301 }
302 }
303
304 func TestCollectDataWithConfigMap(t *testing.T) {
305 caseMappingMode := int32(0400)
306 cases := []struct {
307 name string
308 mappings []v1.KeyToPath
309 configMap *v1.ConfigMap
310 mode int32
311 optional bool
312 payload map[string]util.FileProjection
313 success bool
314 }{
315 {
316 name: "no overrides",
317 configMap: &v1.ConfigMap{
318 Data: map[string]string{
319 "foo": "foo",
320 "bar": "bar",
321 },
322 },
323 mode: 0644,
324 payload: map[string]util.FileProjection{
325 "foo": {Data: []byte("foo"), Mode: 0644},
326 "bar": {Data: []byte("bar"), Mode: 0644},
327 },
328 success: true,
329 },
330 {
331 name: "basic 1",
332 mappings: []v1.KeyToPath{
333 {
334 Key: "foo",
335 Path: "path/to/foo.txt",
336 },
337 },
338 configMap: &v1.ConfigMap{
339 Data: map[string]string{
340 "foo": "foo",
341 "bar": "bar",
342 },
343 },
344 mode: 0644,
345 payload: map[string]util.FileProjection{
346 "path/to/foo.txt": {Data: []byte("foo"), Mode: 0644},
347 },
348 success: true,
349 },
350 {
351 name: "subdirs",
352 mappings: []v1.KeyToPath{
353 {
354 Key: "foo",
355 Path: "path/to/1/2/3/foo.txt",
356 },
357 },
358 configMap: &v1.ConfigMap{
359 Data: map[string]string{
360 "foo": "foo",
361 "bar": "bar",
362 },
363 },
364 mode: 0644,
365 payload: map[string]util.FileProjection{
366 "path/to/1/2/3/foo.txt": {Data: []byte("foo"), Mode: 0644},
367 },
368 success: true,
369 },
370 {
371 name: "subdirs 2",
372 mappings: []v1.KeyToPath{
373 {
374 Key: "foo",
375 Path: "path/to/1/2/3/foo.txt",
376 },
377 },
378 configMap: &v1.ConfigMap{
379 Data: map[string]string{
380 "foo": "foo",
381 "bar": "bar",
382 },
383 },
384 mode: 0644,
385 payload: map[string]util.FileProjection{
386 "path/to/1/2/3/foo.txt": {Data: []byte("foo"), Mode: 0644},
387 },
388 success: true,
389 },
390 {
391 name: "subdirs 3",
392 mappings: []v1.KeyToPath{
393 {
394 Key: "foo",
395 Path: "path/to/1/2/3/foo.txt",
396 },
397 {
398 Key: "bar",
399 Path: "another/path/to/the/esteemed/bar.bin",
400 },
401 },
402 configMap: &v1.ConfigMap{
403 Data: map[string]string{
404 "foo": "foo",
405 "bar": "bar",
406 },
407 },
408 mode: 0644,
409 payload: map[string]util.FileProjection{
410 "path/to/1/2/3/foo.txt": {Data: []byte("foo"), Mode: 0644},
411 "another/path/to/the/esteemed/bar.bin": {Data: []byte("bar"), Mode: 0644},
412 },
413 success: true,
414 },
415 {
416 name: "non existent key",
417 mappings: []v1.KeyToPath{
418 {
419 Key: "zab",
420 Path: "path/to/foo.txt",
421 },
422 },
423 configMap: &v1.ConfigMap{
424 Data: map[string]string{
425 "foo": "foo",
426 "bar": "bar",
427 },
428 },
429 mode: 0644,
430 success: false,
431 },
432 {
433 name: "mapping with Mode",
434 mappings: []v1.KeyToPath{
435 {
436 Key: "foo",
437 Path: "foo.txt",
438 Mode: &caseMappingMode,
439 },
440 {
441 Key: "bar",
442 Path: "bar.bin",
443 Mode: &caseMappingMode,
444 },
445 },
446 configMap: &v1.ConfigMap{
447 Data: map[string]string{
448 "foo": "foo",
449 "bar": "bar",
450 },
451 },
452 mode: 0644,
453 payload: map[string]util.FileProjection{
454 "foo.txt": {Data: []byte("foo"), Mode: caseMappingMode},
455 "bar.bin": {Data: []byte("bar"), Mode: caseMappingMode},
456 },
457 success: true,
458 },
459 {
460 name: "mapping with defaultMode",
461 mappings: []v1.KeyToPath{
462 {
463 Key: "foo",
464 Path: "foo.txt",
465 },
466 {
467 Key: "bar",
468 Path: "bar.bin",
469 },
470 },
471 configMap: &v1.ConfigMap{
472 Data: map[string]string{
473 "foo": "foo",
474 "bar": "bar",
475 },
476 },
477 mode: 0644,
478 payload: map[string]util.FileProjection{
479 "foo.txt": {Data: []byte("foo"), Mode: 0644},
480 "bar.bin": {Data: []byte("bar"), Mode: 0644},
481 },
482 success: true,
483 },
484 {
485 name: "optional non existent key",
486 mappings: []v1.KeyToPath{
487 {
488 Key: "zab",
489 Path: "path/to/foo.txt",
490 },
491 },
492 configMap: &v1.ConfigMap{
493 Data: map[string]string{
494 "foo": "foo",
495 "bar": "bar",
496 },
497 },
498 mode: 0644,
499 optional: true,
500 payload: map[string]util.FileProjection{},
501 success: true,
502 },
503 }
504 for _, tc := range cases {
505 t.Run(tc.name, func(t *testing.T) {
506 testNamespace := "test_projected_namespace"
507 tc.configMap.ObjectMeta = metav1.ObjectMeta{
508 Namespace: testNamespace,
509 Name: tc.name,
510 }
511
512 source := makeProjection(tc.name, utilptr.Int32Ptr(tc.mode), "configMap")
513 source.Sources[0].ConfigMap.Items = tc.mappings
514 source.Sources[0].ConfigMap.Optional = &tc.optional
515
516 testPodUID := types.UID("test_pod_uid")
517 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
518 client := fake.NewSimpleClientset(tc.configMap)
519 tempDir, host := newTestHost(t, client)
520 defer os.RemoveAll(tempDir)
521 var myVolumeMounter = projectedVolumeMounter{
522 projectedVolume: &projectedVolume{
523 sources: source.Sources,
524 podUID: pod.UID,
525 plugin: &projectedPlugin{
526 host: host,
527 getConfigMap: host.GetConfigMapFunc(),
528 },
529 },
530 source: *source,
531 pod: pod,
532 }
533
534 actualPayload, err := myVolumeMounter.collectData(volume.MounterArgs{})
535 if err != nil && tc.success {
536 t.Errorf("%v: unexpected failure making payload: %v", tc.name, err)
537 return
538 }
539 if err == nil && !tc.success {
540 t.Errorf("%v: unexpected success making payload", tc.name)
541 return
542 }
543 if !tc.success {
544 return
545 }
546 if e, a := tc.payload, actualPayload; !reflect.DeepEqual(e, a) {
547 t.Errorf("%v: expected and actual payload do not match", tc.name)
548 }
549 })
550 }
551 }
552
553 func TestCollectDataWithDownwardAPI(t *testing.T) {
554 testNamespace := "test_projected_namespace"
555 testPodUID := types.UID("test_pod_uid")
556 testPodName := "podName"
557
558 cases := []struct {
559 name string
560 volumeFile []v1.DownwardAPIVolumeFile
561 pod *v1.Pod
562 mode int32
563 payload map[string]util.FileProjection
564 success bool
565 }{
566 {
567 name: "annotation",
568 volumeFile: []v1.DownwardAPIVolumeFile{
569 {Path: "annotation", FieldRef: &v1.ObjectFieldSelector{
570 FieldPath: "metadata.annotations['a1']"}}},
571 pod: &v1.Pod{
572 ObjectMeta: metav1.ObjectMeta{
573 Name: testPodName,
574 Namespace: testNamespace,
575 Annotations: map[string]string{
576 "a1": "value1",
577 "a2": "value2",
578 },
579 UID: testPodUID},
580 },
581 mode: 0644,
582 payload: map[string]util.FileProjection{
583 "annotation": {Data: []byte("value1"), Mode: 0644},
584 },
585 success: true,
586 },
587 {
588 name: "annotation-error",
589 volumeFile: []v1.DownwardAPIVolumeFile{
590 {Path: "annotation", FieldRef: &v1.ObjectFieldSelector{
591 FieldPath: "metadata.annotations['']"}}},
592 pod: &v1.Pod{
593 ObjectMeta: metav1.ObjectMeta{
594 Name: testPodName,
595 Namespace: testNamespace,
596 Annotations: map[string]string{
597 "a1": "value1",
598 "a2": "value2",
599 },
600 UID: testPodUID},
601 },
602 mode: 0644,
603 payload: map[string]util.FileProjection{
604 "annotation": {Data: []byte("does-not-matter-because-this-test-case-will-fail-anyway"), Mode: 0644},
605 },
606 success: false,
607 },
608 {
609 name: "labels",
610 volumeFile: []v1.DownwardAPIVolumeFile{
611 {Path: "labels", FieldRef: &v1.ObjectFieldSelector{
612 FieldPath: "metadata.labels"}}},
613 pod: &v1.Pod{
614 ObjectMeta: metav1.ObjectMeta{
615 Name: testPodName,
616 Namespace: testNamespace,
617 Labels: map[string]string{
618 "key1": "value1",
619 "key2": "value2"},
620 UID: testPodUID},
621 },
622 mode: 0644,
623 payload: map[string]util.FileProjection{
624 "labels": {Data: []byte("key1=\"value1\"\nkey2=\"value2\""), Mode: 0644},
625 },
626 success: true,
627 },
628 {
629 name: "annotations",
630 volumeFile: []v1.DownwardAPIVolumeFile{
631 {Path: "annotations", FieldRef: &v1.ObjectFieldSelector{
632 FieldPath: "metadata.annotations"}}},
633 pod: &v1.Pod{
634 ObjectMeta: metav1.ObjectMeta{
635 Name: testPodName,
636 Namespace: testNamespace,
637 Annotations: map[string]string{
638 "a1": "value1",
639 "a2": "value2"},
640 UID: testPodUID},
641 },
642 mode: 0644,
643 payload: map[string]util.FileProjection{
644 "annotations": {Data: []byte("a1=\"value1\"\na2=\"value2\""), Mode: 0644},
645 },
646 success: true,
647 },
648 {
649 name: "name",
650 volumeFile: []v1.DownwardAPIVolumeFile{
651 {Path: "name_file_name", FieldRef: &v1.ObjectFieldSelector{
652 FieldPath: "metadata.name"}}},
653 pod: &v1.Pod{
654 ObjectMeta: metav1.ObjectMeta{
655 Name: testPodName,
656 Namespace: testNamespace,
657 UID: testPodUID},
658 },
659 mode: 0644,
660 payload: map[string]util.FileProjection{
661 "name_file_name": {Data: []byte(testPodName), Mode: 0644},
662 },
663 success: true,
664 },
665 {
666 name: "namespace",
667 volumeFile: []v1.DownwardAPIVolumeFile{
668 {Path: "namespace_file_name", FieldRef: &v1.ObjectFieldSelector{
669 FieldPath: "metadata.namespace"}}},
670 pod: &v1.Pod{
671 ObjectMeta: metav1.ObjectMeta{
672 Name: testPodName,
673 Namespace: testNamespace,
674 UID: testPodUID},
675 },
676 mode: 0644,
677 payload: map[string]util.FileProjection{
678 "namespace_file_name": {Data: []byte(testNamespace), Mode: 0644},
679 },
680 success: true,
681 },
682 }
683
684 for _, tc := range cases {
685 t.Run(tc.name, func(t *testing.T) {
686 source := makeProjection("", utilptr.Int32Ptr(tc.mode), "downwardAPI")
687 source.Sources[0].DownwardAPI.Items = tc.volumeFile
688
689 client := fake.NewSimpleClientset(tc.pod)
690 tempDir, host := newTestHost(t, client)
691 defer os.RemoveAll(tempDir)
692 var myVolumeMounter = projectedVolumeMounter{
693 projectedVolume: &projectedVolume{
694 sources: source.Sources,
695 podUID: tc.pod.UID,
696 plugin: &projectedPlugin{
697 host: host,
698 },
699 },
700 source: *source,
701 pod: tc.pod,
702 }
703
704 actualPayload, err := myVolumeMounter.collectData(volume.MounterArgs{})
705 if err != nil && tc.success {
706 t.Errorf("%v: unexpected failure making payload: %v", tc.name, err)
707 return
708 }
709 if err == nil && !tc.success {
710 t.Errorf("%v: unexpected success making payload", tc.name)
711 return
712 }
713 if !tc.success {
714 return
715 }
716 if e, a := tc.payload, actualPayload; !reflect.DeepEqual(e, a) {
717 t.Errorf("%v: expected and actual payload do not match", tc.name)
718 }
719 })
720
721 }
722 }
723
724 func TestCollectDataWithServiceAccountToken(t *testing.T) {
725 scheme := runtime.NewScheme()
726 utilruntime.Must(pkgauthenticationv1.RegisterDefaults(scheme))
727 utilruntime.Must(pkgcorev1.RegisterDefaults(scheme))
728
729 minute := int64(60)
730 cases := []struct {
731 name string
732 svcacct string
733 audience string
734 defaultMode *int32
735 fsUser *int64
736 fsGroup *int64
737 expiration *int64
738 path string
739
740 wantPayload map[string]util.FileProjection
741 wantErr error
742 }{
743 {
744 name: "good service account",
745 audience: "https://example.com",
746 defaultMode: utilptr.Int32Ptr(0644),
747 path: "token",
748 expiration: &minute,
749
750 wantPayload: map[string]util.FileProjection{
751 "token": {Data: []byte("test_projected_namespace:foo:60:[https://example.com]"), Mode: 0644},
752 },
753 },
754 {
755 name: "good service account other path",
756 audience: "https://example.com",
757 defaultMode: utilptr.Int32Ptr(0644),
758 path: "other-token",
759 expiration: &minute,
760 wantPayload: map[string]util.FileProjection{
761 "other-token": {Data: []byte("test_projected_namespace:foo:60:[https://example.com]"), Mode: 0644},
762 },
763 },
764 {
765 name: "good service account defaults audience",
766 defaultMode: utilptr.Int32Ptr(0644),
767 path: "token",
768 expiration: &minute,
769
770 wantPayload: map[string]util.FileProjection{
771 "token": {Data: []byte("test_projected_namespace:foo:60:[https://api]"), Mode: 0644},
772 },
773 },
774 {
775 name: "good service account defaults expiration",
776 defaultMode: utilptr.Int32Ptr(0644),
777 path: "token",
778
779 wantPayload: map[string]util.FileProjection{
780 "token": {Data: []byte("test_projected_namespace:foo:3600:[https://api]"), Mode: 0644},
781 },
782 },
783 {
784 name: "no default mode",
785 path: "token",
786 wantErr: fmt.Errorf("no defaultMode used, not even the default value for it"),
787 },
788 {
789 name: "fsUser != nil",
790 defaultMode: utilptr.Int32Ptr(0644),
791 fsUser: utilptr.Int64Ptr(1000),
792 path: "token",
793 wantPayload: map[string]util.FileProjection{
794 "token": {
795 Data: []byte("test_projected_namespace:foo:3600:[https://api]"),
796 Mode: 0600,
797 FsUser: utilptr.Int64Ptr(1000),
798 },
799 },
800 },
801 {
802 name: "fsGroup != nil",
803 defaultMode: utilptr.Int32Ptr(0644),
804 fsGroup: utilptr.Int64Ptr(1000),
805 path: "token",
806 wantPayload: map[string]util.FileProjection{
807 "token": {
808 Data: []byte("test_projected_namespace:foo:3600:[https://api]"),
809 Mode: 0600,
810 },
811 },
812 },
813 {
814 name: "fsUser != nil && fsGroup != nil",
815 defaultMode: utilptr.Int32Ptr(0644),
816 fsGroup: utilptr.Int64Ptr(1000),
817 fsUser: utilptr.Int64Ptr(1000),
818 path: "token",
819 wantPayload: map[string]util.FileProjection{
820 "token": {
821 Data: []byte("test_projected_namespace:foo:3600:[https://api]"),
822 Mode: 0600,
823 FsUser: utilptr.Int64Ptr(1000),
824 },
825 },
826 },
827 }
828
829 for _, tc := range cases {
830 t.Run(tc.name, func(t *testing.T) {
831 testNamespace := "test_projected_namespace"
832 source := makeProjection(tc.name, tc.defaultMode, "serviceAccountToken")
833 source.Sources[0].ServiceAccountToken.Audience = tc.audience
834 source.Sources[0].ServiceAccountToken.ExpirationSeconds = tc.expiration
835 source.Sources[0].ServiceAccountToken.Path = tc.path
836
837 testPodUID := types.UID("test_pod_uid")
838 pod := &v1.Pod{
839 ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID},
840 Spec: v1.PodSpec{ServiceAccountName: "foo"},
841 }
842 scheme.Default(pod)
843
844 client := &fake.Clientset{}
845 client.AddReactor("create", "serviceaccounts", clitesting.ReactionFunc(func(action clitesting.Action) (bool, runtime.Object, error) {
846 tr := action.(clitesting.CreateAction).GetObject().(*authenticationv1.TokenRequest)
847 scheme.Default(tr)
848 if len(tr.Spec.Audiences) == 0 {
849 tr.Spec.Audiences = []string{"https://api"}
850 }
851 tr.Status.Token = fmt.Sprintf("%v:%v:%d:%v", action.GetNamespace(), "foo", *tr.Spec.ExpirationSeconds, tr.Spec.Audiences)
852 return true, tr, nil
853 }))
854
855 tempDir, host := newTestHost(t, client)
856 defer os.RemoveAll(tempDir)
857
858 var myVolumeMounter = projectedVolumeMounter{
859 projectedVolume: &projectedVolume{
860 sources: source.Sources,
861 podUID: pod.UID,
862 plugin: &projectedPlugin{
863 host: host,
864 getServiceAccountToken: host.GetServiceAccountTokenFunc(),
865 },
866 },
867 source: *source,
868 pod: pod,
869 }
870
871 gotPayload, err := myVolumeMounter.collectData(volume.MounterArgs{FsUser: tc.fsUser, FsGroup: tc.fsGroup})
872 if err != nil && (tc.wantErr == nil || tc.wantErr.Error() != err.Error()) {
873 t.Fatalf("collectData() = unexpected err: %v", err)
874 }
875 if diff := cmp.Diff(tc.wantPayload, gotPayload); diff != "" {
876 t.Errorf("collectData() = unexpected diff (-want +got):\n%s", diff)
877 }
878 })
879 }
880 }
881
882 func TestCollectDataWithClusterTrustBundle(t *testing.T) {
883
884
885
886
887 goodCert1 := mustMakeRoot(t, "root1")
888
889 testCases := []struct {
890 name string
891
892 source v1.ProjectedVolumeSource
893 bundles []runtime.Object
894
895 fsUser *int64
896 fsGroup *int64
897
898 wantPayload map[string]util.FileProjection
899 wantErr error
900 }{
901 {
902 name: "single ClusterTrustBundle by name",
903 source: v1.ProjectedVolumeSource{
904 Sources: []v1.VolumeProjection{
905 {
906 ClusterTrustBundle: &v1.ClusterTrustBundleProjection{
907 Name: utilptr.String("foo"),
908 Path: "bundle.pem",
909 },
910 },
911 },
912 DefaultMode: utilptr.Int32(0644),
913 },
914 bundles: []runtime.Object{
915 &certificatesv1alpha1.ClusterTrustBundle{
916 ObjectMeta: metav1.ObjectMeta{
917 Name: "foo",
918 },
919 Spec: certificatesv1alpha1.ClusterTrustBundleSpec{
920 TrustBundle: string(goodCert1),
921 },
922 },
923 },
924 wantPayload: map[string]util.FileProjection{
925 "bundle.pem": {
926 Data: []byte(goodCert1),
927 Mode: 0644,
928 },
929 },
930 },
931 {
932 name: "single ClusterTrustBundle by signer name",
933 source: v1.ProjectedVolumeSource{
934 Sources: []v1.VolumeProjection{
935 {
936 ClusterTrustBundle: &v1.ClusterTrustBundleProjection{
937 SignerName: utilptr.String("foo.example/bar"),
938 LabelSelector: &metav1.LabelSelector{
939 MatchLabels: map[string]string{
940 "key": "non-value",
941 },
942 },
943 Path: "bundle.pem",
944 },
945 },
946 },
947 DefaultMode: utilptr.Int32(0644),
948 },
949 bundles: []runtime.Object{
950 &certificatesv1alpha1.ClusterTrustBundle{
951 ObjectMeta: metav1.ObjectMeta{
952 Name: "foo:example:bar",
953 Labels: map[string]string{
954 "key": "value",
955 },
956 },
957 Spec: certificatesv1alpha1.ClusterTrustBundleSpec{
958 SignerName: "foo.example/bar",
959 TrustBundle: string(goodCert1),
960 },
961 },
962 },
963 wantPayload: map[string]util.FileProjection{
964 "bundle.pem": {
965 Data: []byte(goodCert1),
966 Mode: 0644,
967 },
968 },
969 },
970 {
971 name: "single ClusterTrustBundle by name, non-default mode",
972 source: v1.ProjectedVolumeSource{
973 Sources: []v1.VolumeProjection{
974 {
975 ClusterTrustBundle: &v1.ClusterTrustBundleProjection{
976 Name: utilptr.String("foo"),
977 Path: "bundle.pem",
978 },
979 },
980 },
981 DefaultMode: utilptr.Int32(0600),
982 },
983 bundles: []runtime.Object{
984 &certificatesv1alpha1.ClusterTrustBundle{
985 ObjectMeta: metav1.ObjectMeta{
986 Name: "foo",
987 },
988 Spec: certificatesv1alpha1.ClusterTrustBundleSpec{
989 TrustBundle: string(goodCert1),
990 },
991 },
992 },
993 wantPayload: map[string]util.FileProjection{
994 "bundle.pem": {
995 Data: []byte(goodCert1),
996 Mode: 0600,
997 },
998 },
999 },
1000 }
1001
1002 for _, tc := range testCases {
1003 t.Run(tc.name, func(t *testing.T) {
1004 pod := &v1.Pod{
1005 ObjectMeta: metav1.ObjectMeta{
1006 Namespace: "default",
1007 UID: types.UID("test_pod_uid"),
1008 },
1009 Spec: v1.PodSpec{ServiceAccountName: "foo"},
1010 }
1011
1012 client := fake.NewSimpleClientset(tc.bundles...)
1013
1014 tempDir, host := newTestHost(t, client)
1015 defer os.RemoveAll(tempDir)
1016
1017 var myVolumeMounter = projectedVolumeMounter{
1018 projectedVolume: &projectedVolume{
1019 sources: tc.source.Sources,
1020 podUID: pod.UID,
1021 plugin: &projectedPlugin{
1022 host: host,
1023 kvHost: host.(volume.KubeletVolumeHost),
1024 },
1025 },
1026 source: tc.source,
1027 pod: pod,
1028 }
1029
1030 gotPayload, err := myVolumeMounter.collectData(volume.MounterArgs{FsUser: tc.fsUser, FsGroup: tc.fsGroup})
1031 if err != nil {
1032 t.Fatalf("Unexpected failure making payload: %v", err)
1033 }
1034 if diff := cmp.Diff(tc.wantPayload, gotPayload); diff != "" {
1035 t.Fatalf("Bad payload; diff (-want +got)\n%s", diff)
1036 }
1037 })
1038 }
1039 }
1040
1041 func newTestHost(t *testing.T, clientset clientset.Interface) (string, volume.VolumeHost) {
1042 tempDir, err := os.MkdirTemp("", "projected_volume_test.")
1043 if err != nil {
1044 t.Fatalf("can't make a temp rootdir: %v", err)
1045 }
1046
1047 return tempDir, volumetest.NewFakeKubeletVolumeHost(t, tempDir, clientset, emptydir.ProbeVolumePlugins())
1048 }
1049
1050 func TestCanSupport(t *testing.T) {
1051 pluginMgr := volume.VolumePluginMgr{}
1052 tempDir, host := newTestHost(t, nil)
1053 defer os.RemoveAll(tempDir)
1054 pluginMgr.InitPlugins(ProbeVolumePlugins(), nil , host)
1055
1056 plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
1057 if err != nil {
1058 t.Fatal("Can't find the plugin by name")
1059 }
1060 if plugin.GetPluginName() != projectedPluginName {
1061 t.Errorf("Wrong name: %s", plugin.GetPluginName())
1062 }
1063 if !plugin.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{Projected: &v1.ProjectedVolumeSource{}}}}) {
1064 t.Errorf("Expected true")
1065 }
1066 if plugin.CanSupport(&volume.Spec{}) {
1067 t.Errorf("Expected false")
1068 }
1069 }
1070
1071 func TestPlugin(t *testing.T) {
1072 var (
1073 testPodUID = types.UID("test_pod_uid")
1074 testVolumeName = "test_volume_name"
1075 testNamespace = "test_projected_namespace"
1076 testName = "test_projected_name"
1077
1078 volumeSpec = makeVolumeSpec(testVolumeName, testName, 0644)
1079 secret = makeSecret(testNamespace, testName)
1080 client = fake.NewSimpleClientset(&secret)
1081 pluginMgr = volume.VolumePluginMgr{}
1082 rootDir, host = newTestHost(t, client)
1083 )
1084 defer os.RemoveAll(rootDir)
1085 pluginMgr.InitPlugins(ProbeVolumePlugins(), nil , host)
1086
1087 plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
1088 if err != nil {
1089 t.Fatal("Can't find the plugin by name")
1090 }
1091
1092 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
1093 mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
1094 if err != nil {
1095 t.Errorf("Failed to make a new Mounter: %v", err)
1096 }
1097 if mounter == nil {
1098 t.Errorf("Got a nil Mounter")
1099 }
1100
1101 volumePath := mounter.GetPath()
1102 if !strings.HasSuffix(volumePath, filepath.Join("pods/test_pod_uid/volumes/kubernetes.io~projected", testVolumeName)) {
1103 t.Errorf("Got unexpected path: %s", volumePath)
1104 }
1105
1106 err = mounter.SetUp(volume.MounterArgs{})
1107 if err != nil {
1108 t.Errorf("Failed to setup volume: %v", err)
1109 }
1110 if _, err := os.Stat(volumePath); err != nil {
1111 if os.IsNotExist(err) {
1112 t.Errorf("SetUp() failed, volume path not created: %s", volumePath)
1113 } else {
1114 t.Errorf("SetUp() failed: %v", err)
1115 }
1116 }
1117
1118
1119 podWrapperMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid/plugins/kubernetes.io~empty-dir/wrapped_test_volume_name", rootDir)
1120
1121 if _, err := os.Stat(podWrapperMetadataDir); err != nil {
1122 if os.IsNotExist(err) {
1123 t.Errorf("SetUp() failed, empty-dir wrapper path is not created: %s", podWrapperMetadataDir)
1124 } else {
1125 t.Errorf("SetUp() failed: %v", err)
1126 }
1127 }
1128 doTestSecretDataInVolume(volumePath, secret, t)
1129 defer doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
1130 }
1131
1132 func TestInvalidPathProjected(t *testing.T) {
1133 var (
1134 testPodUID = types.UID("test_pod_uid")
1135 testVolumeName = "test_volume_name"
1136 testNamespace = "test_projected_namespace"
1137 testName = "test_projected_name"
1138
1139 volumeSpec = makeVolumeSpec(testVolumeName, testName, 0644)
1140 secret = makeSecret(testNamespace, testName)
1141 client = fake.NewSimpleClientset(&secret)
1142 pluginMgr = volume.VolumePluginMgr{}
1143 rootDir, host = newTestHost(t, client)
1144 )
1145 volumeSpec.Projected.Sources[0].Secret.Items = []v1.KeyToPath{
1146 {Key: "missing", Path: "missing"},
1147 }
1148
1149 defer os.RemoveAll(rootDir)
1150 pluginMgr.InitPlugins(ProbeVolumePlugins(), nil , host)
1151
1152 plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
1153 if err != nil {
1154 t.Fatal("Can't find the plugin by name")
1155 }
1156
1157 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
1158 mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
1159 if err != nil {
1160 t.Errorf("Failed to make a new Mounter: %v", err)
1161 }
1162 if mounter == nil {
1163 t.Errorf("Got a nil Mounter")
1164 }
1165
1166 volumePath := mounter.GetPath()
1167 if !strings.HasSuffix(volumePath, filepath.Join("pods/test_pod_uid/volumes/kubernetes.io~projected", testVolumeName)) {
1168 t.Errorf("Got unexpected path: %s", volumePath)
1169 }
1170
1171 var mounterArgs volume.MounterArgs
1172 err = mounter.SetUp(mounterArgs)
1173 if err == nil {
1174 t.Errorf("Expected error while setting up secret")
1175 }
1176
1177 _, err = os.Stat(volumePath)
1178 if err == nil {
1179 t.Errorf("Expected path %s to not exist", volumePath)
1180 }
1181 }
1182
1183
1184
1185
1186 func TestPluginReboot(t *testing.T) {
1187 var (
1188 testPodUID = types.UID("test_pod_uid3")
1189 testVolumeName = "test_volume_name"
1190 testNamespace = "test_secret_namespace"
1191 testName = "test_secret_name"
1192
1193 volumeSpec = makeVolumeSpec(testVolumeName, testName, 0644)
1194 secret = makeSecret(testNamespace, testName)
1195 client = fake.NewSimpleClientset(&secret)
1196 pluginMgr = volume.VolumePluginMgr{}
1197 rootDir, host = newTestHost(t, client)
1198 )
1199 defer os.RemoveAll(rootDir)
1200 pluginMgr.InitPlugins(ProbeVolumePlugins(), nil , host)
1201
1202 plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
1203 if err != nil {
1204 t.Fatal("Can't find the plugin by name")
1205 }
1206
1207 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
1208 mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
1209 if err != nil {
1210 t.Errorf("Failed to make a new Mounter: %v", err)
1211 }
1212 if mounter == nil {
1213 t.Errorf("Got a nil Mounter")
1214 }
1215
1216 podMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid3/plugins/kubernetes.io~projected/test_volume_name", rootDir)
1217 util.SetReady(podMetadataDir)
1218 volumePath := mounter.GetPath()
1219 if !strings.HasSuffix(volumePath, filepath.FromSlash("pods/test_pod_uid3/volumes/kubernetes.io~projected/test_volume_name")) {
1220 t.Errorf("Got unexpected path: %s", volumePath)
1221 }
1222
1223 err = mounter.SetUp(volume.MounterArgs{})
1224 if err != nil {
1225 t.Errorf("Failed to setup volume: %v", err)
1226 }
1227 if _, err := os.Stat(volumePath); err != nil {
1228 if os.IsNotExist(err) {
1229 t.Errorf("SetUp() failed, volume path not created: %s", volumePath)
1230 } else {
1231 t.Errorf("SetUp() failed: %v", err)
1232 }
1233 }
1234
1235 doTestSecretDataInVolume(volumePath, secret, t)
1236 doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
1237 }
1238
1239 func TestPluginOptional(t *testing.T) {
1240 var (
1241 testPodUID = types.UID("test_pod_uid")
1242 testVolumeName = "test_volume_name"
1243 testNamespace = "test_secret_namespace"
1244 testName = "test_secret_name"
1245 trueVal = true
1246
1247 volumeSpec = makeVolumeSpec(testVolumeName, testName, 0644)
1248 client = fake.NewSimpleClientset()
1249 pluginMgr = volume.VolumePluginMgr{}
1250 rootDir, host = newTestHost(t, client)
1251 )
1252 volumeSpec.VolumeSource.Projected.Sources[0].Secret.Optional = &trueVal
1253 defer os.RemoveAll(rootDir)
1254 pluginMgr.InitPlugins(ProbeVolumePlugins(), nil , host)
1255
1256 plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
1257 if err != nil {
1258 t.Fatal("Can't find the plugin by name")
1259 }
1260
1261 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
1262 mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
1263 if err != nil {
1264 t.Errorf("Failed to make a new Mounter: %v", err)
1265 }
1266 if mounter == nil {
1267 t.Errorf("Got a nil Mounter")
1268 }
1269
1270 volumePath := mounter.GetPath()
1271 if !strings.HasSuffix(volumePath, filepath.FromSlash("pods/test_pod_uid/volumes/kubernetes.io~projected/test_volume_name")) {
1272 t.Errorf("Got unexpected path: %s", volumePath)
1273 }
1274
1275 err = mounter.SetUp(volume.MounterArgs{})
1276 if err != nil {
1277 t.Errorf("Failed to setup volume: %v", err)
1278 }
1279 if _, err := os.Stat(volumePath); err != nil {
1280 if os.IsNotExist(err) {
1281 t.Errorf("SetUp() failed, volume path not created: %s", volumePath)
1282 } else {
1283 t.Errorf("SetUp() failed: %v", err)
1284 }
1285 }
1286
1287
1288 podWrapperMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid/plugins/kubernetes.io~empty-dir/wrapped_test_volume_name", rootDir)
1289
1290 if _, err := os.Stat(podWrapperMetadataDir); err != nil {
1291 if os.IsNotExist(err) {
1292 t.Errorf("SetUp() failed, empty-dir wrapper path is not created: %s", podWrapperMetadataDir)
1293 } else {
1294 t.Errorf("SetUp() failed: %v", err)
1295 }
1296 }
1297
1298 datadirSymlink := filepath.Join(volumePath, "..data")
1299 datadir, err := os.Readlink(datadirSymlink)
1300 if err != nil && os.IsNotExist(err) {
1301 t.Fatalf("couldn't find volume path's data dir, %s", datadirSymlink)
1302 } else if err != nil {
1303 t.Fatalf("couldn't read symlink, %s", datadirSymlink)
1304 }
1305 datadirPath := filepath.Join(volumePath, datadir)
1306
1307 infos, err := os.ReadDir(volumePath)
1308 if err != nil {
1309 t.Fatalf("couldn't find volume path, %s", volumePath)
1310 }
1311 if len(infos) != 0 {
1312 for _, fi := range infos {
1313 if fi.Name() != "..data" && fi.Name() != datadir {
1314 t.Errorf("empty data volume directory, %s, is not empty. Contains: %s", datadirSymlink, fi.Name())
1315 }
1316 }
1317 }
1318
1319 infos, err = os.ReadDir(datadirPath)
1320 if err != nil {
1321 t.Fatalf("couldn't find volume data path, %s", datadirPath)
1322 }
1323 if len(infos) != 0 {
1324 t.Errorf("empty data directory, %s, is not empty. Contains: %s", datadirSymlink, infos[0].Name())
1325 }
1326
1327 defer doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
1328 }
1329
1330 func TestPluginOptionalKeys(t *testing.T) {
1331 var (
1332 testPodUID = types.UID("test_pod_uid")
1333 testVolumeName = "test_volume_name"
1334 testNamespace = "test_secret_namespace"
1335 testName = "test_secret_name"
1336 trueVal = true
1337
1338 volumeSpec = makeVolumeSpec(testVolumeName, testName, 0644)
1339 secret = makeSecret(testNamespace, testName)
1340 client = fake.NewSimpleClientset(&secret)
1341 pluginMgr = volume.VolumePluginMgr{}
1342 rootDir, host = newTestHost(t, client)
1343 )
1344 volumeSpec.VolumeSource.Projected.Sources[0].Secret.Items = []v1.KeyToPath{
1345 {Key: "data-1", Path: "data-1"},
1346 {Key: "data-2", Path: "data-2"},
1347 {Key: "data-3", Path: "data-3"},
1348 {Key: "missing", Path: "missing"},
1349 }
1350 volumeSpec.VolumeSource.Projected.Sources[0].Secret.Optional = &trueVal
1351 defer os.RemoveAll(rootDir)
1352 pluginMgr.InitPlugins(ProbeVolumePlugins(), nil , host)
1353
1354 plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
1355 if err != nil {
1356 t.Fatal("Can't find the plugin by name")
1357 }
1358
1359 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, UID: testPodUID}}
1360 mounter, err := plugin.NewMounter(volume.NewSpecFromVolume(volumeSpec), pod, volume.VolumeOptions{})
1361 if err != nil {
1362 t.Errorf("Failed to make a new Mounter: %v", err)
1363 }
1364 if mounter == nil {
1365 t.Errorf("Got a nil Mounter")
1366 }
1367
1368 volumePath := mounter.GetPath()
1369 if !strings.HasSuffix(volumePath, filepath.FromSlash("pods/test_pod_uid/volumes/kubernetes.io~projected/test_volume_name")) {
1370 t.Errorf("Got unexpected path: %s", volumePath)
1371 }
1372
1373 err = mounter.SetUp(volume.MounterArgs{})
1374 if err != nil {
1375 t.Errorf("Failed to setup volume: %v", err)
1376 }
1377 if _, err := os.Stat(volumePath); err != nil {
1378 if os.IsNotExist(err) {
1379 t.Errorf("SetUp() failed, volume path not created: %s", volumePath)
1380 } else {
1381 t.Errorf("SetUp() failed: %v", err)
1382 }
1383 }
1384
1385
1386 podWrapperMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid/plugins/kubernetes.io~empty-dir/wrapped_test_volume_name", rootDir)
1387
1388 if _, err := os.Stat(podWrapperMetadataDir); err != nil {
1389 if os.IsNotExist(err) {
1390 t.Errorf("SetUp() failed, empty-dir wrapper path is not created: %s", podWrapperMetadataDir)
1391 } else {
1392 t.Errorf("SetUp() failed: %v", err)
1393 }
1394 }
1395 doTestSecretDataInVolume(volumePath, secret, t)
1396 defer doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
1397 }
1398
1399 func makeVolumeSpec(volumeName, name string, defaultMode int32) *v1.Volume {
1400 return &v1.Volume{
1401 Name: volumeName,
1402 VolumeSource: v1.VolumeSource{
1403 Projected: makeProjection(name, utilptr.Int32Ptr(defaultMode), "secret"),
1404 },
1405 }
1406 }
1407
1408 func makeSecret(namespace, name string) v1.Secret {
1409 return v1.Secret{
1410 ObjectMeta: metav1.ObjectMeta{
1411 Namespace: namespace,
1412 Name: name,
1413 },
1414 Data: map[string][]byte{
1415 "data-1": []byte("value-1"),
1416 "data-2": []byte("value-2"),
1417 "data-3": []byte("value-3"),
1418 },
1419 }
1420 }
1421
1422 func makeProjection(name string, defaultMode *int32, kind string) *v1.ProjectedVolumeSource {
1423 var item v1.VolumeProjection
1424
1425 switch kind {
1426 case "configMap":
1427 item = v1.VolumeProjection{
1428 ConfigMap: &v1.ConfigMapProjection{
1429 LocalObjectReference: v1.LocalObjectReference{Name: name},
1430 },
1431 }
1432 case "secret":
1433 item = v1.VolumeProjection{
1434 Secret: &v1.SecretProjection{
1435 LocalObjectReference: v1.LocalObjectReference{Name: name},
1436 },
1437 }
1438 case "downwardAPI":
1439 item = v1.VolumeProjection{
1440 DownwardAPI: &v1.DownwardAPIProjection{},
1441 }
1442 case "serviceAccountToken":
1443 item = v1.VolumeProjection{
1444 ServiceAccountToken: &v1.ServiceAccountTokenProjection{},
1445 }
1446 }
1447
1448 return &v1.ProjectedVolumeSource{
1449 Sources: []v1.VolumeProjection{item},
1450 DefaultMode: defaultMode,
1451 }
1452 }
1453
1454 func doTestSecretDataInVolume(volumePath string, secret v1.Secret, t *testing.T) {
1455 for key, value := range secret.Data {
1456 secretDataHostPath := filepath.Join(volumePath, key)
1457 if _, err := os.Stat(secretDataHostPath); err != nil {
1458 t.Fatalf("SetUp() failed, couldn't find secret data on disk: %v", secretDataHostPath)
1459 } else {
1460 actualSecretBytes, err := os.ReadFile(secretDataHostPath)
1461 if err != nil {
1462 t.Fatalf("Couldn't read secret data from: %v", secretDataHostPath)
1463 }
1464
1465 actualSecretValue := string(actualSecretBytes)
1466 if string(value) != actualSecretValue {
1467 t.Errorf("Unexpected value; expected %q, got %q", value, actualSecretValue)
1468 }
1469 }
1470 }
1471 }
1472
1473 func doTestCleanAndTeardown(plugin volume.VolumePlugin, podUID types.UID, testVolumeName, volumePath string, t *testing.T) {
1474 unmounter, err := plugin.NewUnmounter(testVolumeName, podUID)
1475 if err != nil {
1476 t.Errorf("Failed to make a new Unmounter: %v", err)
1477 }
1478 if unmounter == nil {
1479 t.Errorf("Got a nil Unmounter")
1480 }
1481
1482 if err := unmounter.TearDown(); err != nil {
1483 t.Errorf("Expected success, got: %v", err)
1484 }
1485 if _, err := os.Stat(volumePath); err == nil {
1486 t.Errorf("TearDown() failed, volume path still exists: %s", volumePath)
1487 } else if !os.IsNotExist(err) {
1488 t.Errorf("TearDown() failed: %v", err)
1489 }
1490 }
1491
1492 func mustMakeRoot(t *testing.T, cn string) string {
1493 pub, priv, err := ed25519.GenerateKey(rand.Reader)
1494 if err != nil {
1495 t.Fatalf("Error while generating key: %v", err)
1496 }
1497
1498 template := &x509.Certificate{
1499 SerialNumber: big.NewInt(0),
1500 Subject: pkix.Name{
1501 CommonName: cn,
1502 },
1503 IsCA: true,
1504 BasicConstraintsValid: true,
1505 }
1506
1507 cert, err := x509.CreateCertificate(rand.Reader, template, template, pub, priv)
1508 if err != nil {
1509 t.Fatalf("Error while making certificate: %v", err)
1510 }
1511
1512 return string(pem.EncodeToMemory(&pem.Block{
1513 Type: "CERTIFICATE",
1514 Headers: nil,
1515 Bytes: cert,
1516 }))
1517 }
1518
View as plain text