Skip to content

Commit 7f9e6b1

Browse files
authored
fix: cannot start plugin on windows (#758)
Co-authored-by: rick <LinuxSuRen@users.noreply.github.com>
1 parent bef1f3f commit 7f9e6b1

File tree

1 file changed

+152
-147
lines changed

1 file changed

+152
-147
lines changed

pkg/server/store_ext_manager.go

Lines changed: 152 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -16,183 +16,188 @@ limitations under the License.
1616
package server
1717

1818
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"
3737
)
3838

3939
var (
40-
serverLogger = logging.DefaultLogger(logging.LogLevelInfo).WithName("server")
40+
serverLogger = logging.DefaultLogger(logging.LogLevelInfo).WithName("server")
4141
)
4242

4343
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)
4747
}
4848

4949
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
5959
}
6060

6161
var ss *storeExtManager
6262

6363
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
7777
}
7878

7979
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
9191
}
9292

9393
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
130135
}
131136

132137
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
139144

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()
144149

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
149154
}
150155

151156
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
157162
}
158163

159164
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
173178
}
174179

175180
// isWindows returns true if the program is running on Windows OS.
176181
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"))
179184
}
180185

181186
func (s *storeExtManager) WithDownloader(ociDownloader downloader.PlatformAwareOCIDownloader) {
182-
s.ociDownloader = ociDownloader
187+
s.ociDownloader = ociDownloader
183188
}
184189

185190
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+
}()
196201
}
197202

198203
var ErrDownloadNotSupport = errors.New("no support")
@@ -202,44 +207,44 @@ type nonDownloader struct{}
202207
var _ downloader.PlatformAwareOCIDownloader = &nonDownloader{}
203208

204209
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
206211
}
207212

208213
func (n *nonDownloader) Download(image, tag, file string) (reader io.Reader, err error) {
209-
err = ErrDownloadNotSupport
210-
return
214+
err = ErrDownloadNotSupport
215+
return
211216
}
212217

213218
func (n *nonDownloader) WithOS(string) {
214-
// Do nothing because this is an empty implementation
219+
// Do nothing because this is an empty implementation
215220
}
216221

217222
func (n *nonDownloader) WithArch(string) {
218-
// Do nothing because this is an empty implementation
223+
// Do nothing because this is an empty implementation
219224
}
220225

221226
func (n *nonDownloader) WithRegistry(string) {
222-
// Do nothing because this is an empty implementation
227+
// Do nothing because this is an empty implementation
223228
}
224229

225230
func (n *nonDownloader) WithKind(string) {
226-
// Do nothing because this is an empty implementation
231+
// Do nothing because this is an empty implementation
227232
}
228233

229234
func (n *nonDownloader) WithImagePrefix(imagePrefix string) {
230-
// Do nothing because this is an empty implementation
235+
// Do nothing because this is an empty implementation
231236
}
232237
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
234239
}
235240

236241
func (d *nonDownloader) WithInsecure(bool) {
237-
// Do nothing because this is an empty implementation
242+
// Do nothing because this is an empty implementation
238243
}
239244

240245
func (d *nonDownloader) WithTimeout(time.Duration) {}
241246
func (d *nonDownloader) WithContext(context.Context) {}
242247

243248
func (n *nonDownloader) GetTargetFile() string {
244-
return ""
249+
return ""
245250
}

0 commit comments

Comments
 (0)