@@ -16,183 +16,188 @@ limitations under the License.
16
16
package server
17
17
18
18
import (
19
- "context"
20
- "errors"
21
- "fmt"
22
- "io"
23
- "net/http"
24
- "os"
25
- "path/filepath"
26
- "strings"
27
- sync "sync"
28
- "syscall"
29
- "time"
30
-
31
- "github.com/linuxsuren/api-testing/pkg/util/home"
32
-
33
- "github.com/linuxsuren/api-testing/pkg/downloader"
34
- "github.com/linuxsuren/api-testing/pkg/logging"
35
-
36
- fakeruntime "github.com/linuxsuren/go-fake-runtime"
19
+ "context"
20
+ "errors"
21
+ "fmt"
22
+ "io"
23
+ "net/http"
24
+ "os"
25
+ "path/filepath"
26
+ "strings"
27
+ sync "sync"
28
+ "syscall"
29
+ "time"
30
+
31
+ "github.com/linuxsuren/api-testing/pkg/util/home"
32
+
33
+ "github.com/linuxsuren/api-testing/pkg/downloader"
34
+ "github.com/linuxsuren/api-testing/pkg/logging"
35
+
36
+ fakeruntime "github.com/linuxsuren/go-fake-runtime"
37
37
)
38
38
39
39
var (
40
- serverLogger = logging .DefaultLogger (logging .LogLevelInfo ).WithName ("server" )
40
+ serverLogger = logging .DefaultLogger (logging .LogLevelInfo ).WithName ("server" )
41
41
)
42
42
43
43
type ExtManager interface {
44
- Start (name , socket string ) (err error )
45
- StopAll () (err error )
46
- WithDownloader (downloader.PlatformAwareOCIDownloader )
44
+ Start (name , socket string ) (err error )
45
+ StopAll () (err error )
46
+ WithDownloader (downloader.PlatformAwareOCIDownloader )
47
47
}
48
48
49
49
type storeExtManager struct {
50
- execer fakeruntime.Execer
51
- ociDownloader downloader.PlatformAwareOCIDownloader
52
- socketPrefix string
53
- filesNeedToBeRemoved []string
54
- extStatusMap map [string ]bool
55
- processs []fakeruntime.Process
56
- processChan chan fakeruntime.Process
57
- stopSingal chan struct {}
58
- lock * sync.RWMutex
50
+ execer fakeruntime.Execer
51
+ ociDownloader downloader.PlatformAwareOCIDownloader
52
+ socketPrefix string
53
+ filesNeedToBeRemoved []string
54
+ extStatusMap map [string ]bool
55
+ processs []fakeruntime.Process
56
+ processChan chan fakeruntime.Process
57
+ stopSingal chan struct {}
58
+ lock * sync.RWMutex
59
59
}
60
60
61
61
var ss * storeExtManager
62
62
63
63
func NewStoreExtManager (execer fakeruntime.Execer ) ExtManager {
64
- if ss == nil {
65
- ss = & storeExtManager {
66
- processChan : make (chan fakeruntime.Process ),
67
- stopSingal : make (chan struct {}, 1 ),
68
- lock : & sync.RWMutex {},
69
- }
70
- ss .execer = execer
71
- ss .socketPrefix = "unix://"
72
- ss .extStatusMap = map [string ]bool {}
73
- ss .processCollect ()
74
- ss .WithDownloader (& nonDownloader {})
75
- }
76
- return ss
64
+ if ss == nil {
65
+ ss = & storeExtManager {
66
+ processChan : make (chan fakeruntime.Process ),
67
+ stopSingal : make (chan struct {}, 1 ),
68
+ lock : & sync.RWMutex {},
69
+ }
70
+ ss .execer = execer
71
+ ss .socketPrefix = "unix://"
72
+ ss .extStatusMap = map [string ]bool {}
73
+ ss .processCollect ()
74
+ ss .WithDownloader (& nonDownloader {})
75
+ }
76
+ return ss
77
77
}
78
78
79
79
func NewStoreExtManagerInstance (execer fakeruntime.Execer ) ExtManager {
80
- ss = & storeExtManager {
81
- processChan : make (chan fakeruntime.Process ),
82
- stopSingal : make (chan struct {}, 1 ),
83
- lock : & sync.RWMutex {},
84
- }
85
- ss .execer = execer
86
- ss .socketPrefix = "unix://"
87
- ss .extStatusMap = map [string ]bool {}
88
- ss .processCollect ()
89
- ss .WithDownloader (& nonDownloader {})
90
- return ss
80
+ ss = & storeExtManager {
81
+ processChan : make (chan fakeruntime.Process ),
82
+ stopSingal : make (chan struct {}, 1 ),
83
+ lock : & sync.RWMutex {},
84
+ }
85
+ ss .execer = execer
86
+ ss .socketPrefix = "unix://"
87
+ ss .extStatusMap = map [string ]bool {}
88
+ ss .processCollect ()
89
+ ss .WithDownloader (& nonDownloader {})
90
+ return ss
91
91
}
92
92
93
93
func (s * storeExtManager ) Start (name , socket string ) (err error ) {
94
- if v , ok := s .extStatusMap [name ]; ok && v {
95
- return
96
- }
97
- targetDir := home .GetUserBinDir ()
98
- targetBinaryFile := filepath .Join (targetDir , name )
99
-
100
- var binaryPath string
101
- if _ , err = os .Stat (targetBinaryFile ); err == nil {
102
- binaryPath = targetBinaryFile
103
- } else {
104
- binaryPath , err = s .execer .LookPath (name )
105
- if err != nil {
106
- err = fmt .Errorf ("not found extension, try to download it, error: %v" , err )
107
- go func () {
108
- reader , dErr := s .ociDownloader .Download (name , "" , "" )
109
- if dErr != nil {
110
- serverLogger .Error (dErr , "failed to download extension" , "name" , name )
111
- } else {
112
- extFile := s .ociDownloader .GetTargetFile ()
113
-
114
- targetFile := filepath .Base (extFile )
115
- if dErr = downloader .WriteTo (reader , targetDir , targetFile ); dErr == nil {
116
- binaryPath = filepath .Join (targetDir , targetFile )
117
- s .startPlugin (socket , binaryPath , name )
118
- } else {
119
- serverLogger .Error (dErr , "failed to save extension" , "targetFile" , targetFile )
120
- }
121
- }
122
- }()
123
- }
124
- }
125
-
126
- if err == nil {
127
- go s .startPlugin (socket , binaryPath , name )
128
- }
129
- return
94
+ if v , ok := s .extStatusMap [name ]; ok && v {
95
+ return
96
+ }
97
+ if s .execer .OS () == "windows" {
98
+ name = name + ".exe"
99
+ }
100
+ targetDir := home .GetUserBinDir ()
101
+ targetBinaryFile := filepath .Join (targetDir , name )
102
+
103
+ var binaryPath string
104
+ if _ , err = os .Stat (targetBinaryFile ); err == nil {
105
+ binaryPath = targetBinaryFile
106
+ } else {
107
+ serverLogger .Info ("failed to find extension" , "error" , err .Error ())
108
+
109
+ binaryPath , err = s .execer .LookPath (name )
110
+ if err != nil {
111
+ err = fmt .Errorf ("not found extension, try to download it, error: %v" , err )
112
+ go func () {
113
+ reader , dErr := s .ociDownloader .Download (name , "" , "" )
114
+ if dErr != nil {
115
+ serverLogger .Error (dErr , "failed to download extension" , "name" , name )
116
+ } else {
117
+ extFile := s .ociDownloader .GetTargetFile ()
118
+
119
+ targetFile := filepath .Base (extFile )
120
+ if dErr = downloader .WriteTo (reader , targetDir , targetFile ); dErr == nil {
121
+ binaryPath = filepath .Join (targetDir , targetFile )
122
+ s .startPlugin (socket , binaryPath , name )
123
+ } else {
124
+ serverLogger .Error (dErr , "failed to save extension" , "targetFile" , targetFile )
125
+ }
126
+ }
127
+ }()
128
+ }
129
+ }
130
+
131
+ if err == nil {
132
+ go s .startPlugin (socket , binaryPath , name )
133
+ }
134
+ return
130
135
}
131
136
132
137
func (s * storeExtManager ) startPlugin (socketURL , plugin , pluginName string ) (err error ) {
133
- if strings .Contains (socketURL , ":" ) && ! strings .HasPrefix (socketURL , s .socketPrefix ) {
134
- err = s .startPluginViaHTTP (socketURL , plugin , pluginName )
135
- return
136
- }
137
- socketFile := strings .TrimPrefix (socketURL , s .socketPrefix )
138
- _ = os .RemoveAll (socketFile ) // always deleting the socket file to avoid start failing
138
+ if strings .Contains (socketURL , ":" ) && ! strings .HasPrefix (socketURL , s .socketPrefix ) {
139
+ err = s .startPluginViaHTTP (socketURL , plugin , pluginName )
140
+ return
141
+ }
142
+ socketFile := strings .TrimPrefix (socketURL , s .socketPrefix )
143
+ _ = os .RemoveAll (socketFile ) // always deleting the socket file to avoid start failing
139
144
140
- s .lock .Lock ()
141
- s .filesNeedToBeRemoved = append (s .filesNeedToBeRemoved , socketFile )
142
- s .extStatusMap [pluginName ] = true
143
- s .lock .Unlock ()
145
+ s .lock .Lock ()
146
+ s .filesNeedToBeRemoved = append (s .filesNeedToBeRemoved , socketFile )
147
+ s .extStatusMap [pluginName ] = true
148
+ s .lock .Unlock ()
144
149
145
- if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--socket" , socketFile ); err != nil {
146
- serverLogger .Info ("failed to start ext manager" , "socket" , socketURL , "error: " , err .Error ())
147
- }
148
- return
150
+ if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--socket" , socketFile ); err != nil {
151
+ serverLogger .Info ("failed to start ext manager" , "socket" , socketURL , "error: " , err .Error ())
152
+ }
153
+ return
149
154
}
150
155
151
156
func (s * storeExtManager ) startPluginViaHTTP (httpURL , plugin , pluginName string ) (err error ) {
152
- port := strings .Split (httpURL , ":" )[1 ]
153
- if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--port" , port ); err != nil {
154
- serverLogger .Info ("failed to start ext manager" , "port" , port , "error: " , err .Error ())
155
- }
156
- return
157
+ port := strings .Split (httpURL , ":" )[1 ]
158
+ if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--port" , port ); err != nil {
159
+ serverLogger .Info ("failed to start ext manager" , "port" , port , "error: " , err .Error ())
160
+ }
161
+ return
157
162
}
158
163
159
164
func (s * storeExtManager ) StopAll () error {
160
- serverLogger .Info ("stop" , "extensions" , len (s .processs ))
161
- for _ , p := range s .processs {
162
- if p != nil {
163
- // Use Kill on Windows, Signal on other platforms
164
- if isWindows () {
165
- p .Kill ()
166
- } else {
167
- p .Signal (syscall .SIGTERM )
168
- }
169
- }
170
- }
171
- s .stopSingal <- struct {}{}
172
- return nil
165
+ serverLogger .Info ("stop" , "extensions" , len (s .processs ))
166
+ for _ , p := range s .processs {
167
+ if p != nil {
168
+ // Use Kill on Windows, Signal on other platforms
169
+ if isWindows () {
170
+ p .Kill ()
171
+ } else {
172
+ p .Signal (syscall .SIGTERM )
173
+ }
174
+ }
175
+ }
176
+ s .stopSingal <- struct {}{}
177
+ return nil
173
178
}
174
179
175
180
// isWindows returns true if the program is running on Windows OS.
176
181
func isWindows () bool {
177
- return strings .Contains (strings .ToLower (os .Getenv ("OS" )), "windows" ) ||
178
- (strings .Contains (strings .ToLower (os .Getenv ("GOOS" )), "windows" ))
182
+ return strings .Contains (strings .ToLower (os .Getenv ("OS" )), "windows" ) ||
183
+ (strings .Contains (strings .ToLower (os .Getenv ("GOOS" )), "windows" ))
179
184
}
180
185
181
186
func (s * storeExtManager ) WithDownloader (ociDownloader downloader.PlatformAwareOCIDownloader ) {
182
- s .ociDownloader = ociDownloader
187
+ s .ociDownloader = ociDownloader
183
188
}
184
189
185
190
func (s * storeExtManager ) processCollect () {
186
- go func () {
187
- for {
188
- select {
189
- case p := <- s .processChan :
190
- s .processs = append (s .processs , p )
191
- case <- s .stopSingal :
192
- return
193
- }
194
- }
195
- }()
191
+ go func () {
192
+ for {
193
+ select {
194
+ case p := <- s .processChan :
195
+ s .processs = append (s .processs , p )
196
+ case <- s .stopSingal :
197
+ return
198
+ }
199
+ }
200
+ }()
196
201
}
197
202
198
203
var ErrDownloadNotSupport = errors .New ("no support" )
@@ -202,44 +207,44 @@ type nonDownloader struct{}
202
207
var _ downloader.PlatformAwareOCIDownloader = & nonDownloader {}
203
208
204
209
func (n * nonDownloader ) WithBasicAuth (username string , password string ) {
205
- // Do nothing because this is an empty implementation
210
+ // Do nothing because this is an empty implementation
206
211
}
207
212
208
213
func (n * nonDownloader ) Download (image , tag , file string ) (reader io.Reader , err error ) {
209
- err = ErrDownloadNotSupport
210
- return
214
+ err = ErrDownloadNotSupport
215
+ return
211
216
}
212
217
213
218
func (n * nonDownloader ) WithOS (string ) {
214
- // Do nothing because this is an empty implementation
219
+ // Do nothing because this is an empty implementation
215
220
}
216
221
217
222
func (n * nonDownloader ) WithArch (string ) {
218
- // Do nothing because this is an empty implementation
223
+ // Do nothing because this is an empty implementation
219
224
}
220
225
221
226
func (n * nonDownloader ) WithRegistry (string ) {
222
- // Do nothing because this is an empty implementation
227
+ // Do nothing because this is an empty implementation
223
228
}
224
229
225
230
func (n * nonDownloader ) WithKind (string ) {
226
- // Do nothing because this is an empty implementation
231
+ // Do nothing because this is an empty implementation
227
232
}
228
233
229
234
func (n * nonDownloader ) WithImagePrefix (imagePrefix string ) {
230
- // Do nothing because this is an empty implementation
235
+ // Do nothing because this is an empty implementation
231
236
}
232
237
func (d * nonDownloader ) WithRoundTripper (rt http.RoundTripper ) {
233
- // Do nothing because this is an empty implementation
238
+ // Do nothing because this is an empty implementation
234
239
}
235
240
236
241
func (d * nonDownloader ) WithInsecure (bool ) {
237
- // Do nothing because this is an empty implementation
242
+ // Do nothing because this is an empty implementation
238
243
}
239
244
240
245
func (d * nonDownloader ) WithTimeout (time.Duration ) {}
241
246
func (d * nonDownloader ) WithContext (context.Context ) {}
242
247
243
248
func (n * nonDownloader ) GetTargetFile () string {
244
- return ""
249
+ return ""
245
250
}
0 commit comments