@@ -19,6 +19,7 @@ package cdi
19
19
import (
20
20
"fmt"
21
21
"os"
22
+ "path/filepath"
22
23
"strconv"
23
24
"strings"
24
25
"syscall"
@@ -48,6 +49,100 @@ func TestTooManyOpenFiles(t *testing.T) {
48
49
_ , _ = cache .InjectDevices (& oci.Spec {}, "vendor1.com/device=dev1" )
49
50
}
50
51
52
+ func TestRecoveryAfterTooManyOpenFiles (t * testing.T ) {
53
+ var (
54
+ etcDir = map [string ]string {
55
+ "vendor1.yaml" : `
56
+ cdiVersion: "0.3.0"
57
+ kind: "vendor1.com/device"
58
+ containerEdits:
59
+ env:
60
+ - VENDOR1_SPEC_VAR1=VAL1
61
+ devices:
62
+ - name: "dev1"
63
+ containerEdits:
64
+ env:
65
+ - "VENDOR1_VAR1=VAL1"
66
+ deviceNodes:
67
+ - path: "/dev/vendor1-dev1"
68
+ type: b
69
+ major: 10
70
+ minor: 1
71
+ ` ,
72
+ }
73
+
74
+ devices = []string {
75
+ "vendor1.com/device=dev1" ,
76
+ }
77
+
78
+ ociSpec = & oci.Spec {}
79
+
80
+ resultingSpec = & oci.Spec {
81
+ Process : & oci.Process {
82
+ Env : []string {
83
+ "VENDOR1_SPEC_VAR1=VAL1" ,
84
+ "VENDOR1_VAR1=VAL1" ,
85
+ },
86
+ },
87
+ Linux : & oci.Linux {
88
+ Devices : []oci.LinuxDevice {
89
+ {
90
+ Path : "/dev/vendor1-dev1" ,
91
+ Type : "b" ,
92
+ Major : 10 ,
93
+ Minor : 1 ,
94
+ },
95
+ },
96
+ Resources : & oci.LinuxResources {
97
+ Devices : []oci.LinuxDeviceCgroup {
98
+ {
99
+ Allow : true ,
100
+ Type : "b" ,
101
+ Major : int64ptr (10 ),
102
+ Minor : int64ptr (1 ),
103
+ Access : "rwm" ,
104
+ },
105
+ },
106
+ },
107
+ },
108
+ }
109
+ )
110
+
111
+ dir , err := createSpecDirs (t , etcDir , nil )
112
+ require .NoError (t , err , "failed to create test directory" )
113
+
114
+ // trigger EMFILE for fd creation: exhaust our file descriptor table
115
+ em , err := triggerEmfile ()
116
+ require .NoError (t , err )
117
+ require .NotNil (t , em )
118
+ defer func () {
119
+ require .NoError (t , em .undo ())
120
+ }()
121
+
122
+ _ , err = syscall .Socket (syscall .AF_INET , syscall .SOCK_DGRAM , 0 )
123
+ require .Equal (t , syscall .EMFILE , err )
124
+
125
+ cache := newCache (
126
+ WithSpecDirs (
127
+ filepath .Join (dir , "etc" ),
128
+ ),
129
+ WithAutoRefresh (true ),
130
+ )
131
+ require .NotNil (t , cache )
132
+
133
+ // try to trigger original crash with a nil fsnotify.Watcher
134
+ _ , _ = cache .InjectDevices (& oci.Spec {}, devices ... )
135
+
136
+ // undo EMFILE for fd creation
137
+ require .NoError (t , em .undo ())
138
+
139
+ // verify that injection works again
140
+ unresolved , err := cache .InjectDevices (ociSpec , devices ... )
141
+ require .NoError (t , err )
142
+ require .Nil (t , unresolved )
143
+ require .Equal (t , resultingSpec , ociSpec )
144
+ }
145
+
51
146
type emfile struct {
52
147
limit syscall.Rlimit
53
148
fds []int
0 commit comments