44 "bufio"
55 "io"
66 "os/exec"
7- "path"
87 "strings"
98 "syscall"
109 "time"
@@ -14,27 +13,123 @@ import (
1413)
1514
1615const (
17- CommandTimeout = 60 * time .Second
16+ StartCommandWait = 30 * time .Second
17+ RunCommandTimeout = 60 * time .Second
1818)
1919
2020var (
2121 StartupDate = time .Now ().Format ("20060102-150405" )
2222)
2323
24- // run command with tty support
24+ // start command with tty support and wait for some time before returning output
25+ // the command will keep running after this call
26+ func StartCommand (log * logrus.Entry , commandName string , arg ... string ) (string , error ) {
27+ log .WithFields (logrus.Fields {"cmd" : commandName , "arg" : arg }).Info ("Starting command" )
28+
29+ cmd := exec .Command (commandName , arg ... )
30+ cmd .Env = append (cmd .Environ (), "isE2E=true" )
31+
32+ outPipe , _ := cmd .StdoutPipe ()
33+ errPipe , _ := cmd .StderrPipe ()
34+
35+ var sb strings.Builder
36+ go func (_ io.ReadCloser ) {
37+ reader := bufio .NewReader (errPipe )
38+ line , err := reader .ReadString ('\n' )
39+ for err == nil {
40+ sb .WriteString (line )
41+ line , err = reader .ReadString ('\n' )
42+ }
43+ }(errPipe )
44+
45+ go func (_ io.ReadCloser ) {
46+ reader := bufio .NewReader (outPipe )
47+ line , err := reader .ReadString ('\n' )
48+ for err == nil {
49+ sb .WriteString (line )
50+ line , err = reader .ReadString ('\n' )
51+ }
52+ }(outPipe )
53+
54+ // start async
55+ go func () {
56+ log .Debug ("Starting async ..." )
57+ _ , err := pty .Start (cmd )
58+ if err != nil {
59+ log .Errorf ("Start returned error: %v" , err )
60+ }
61+ }()
62+
63+ log .Debugf ("Waiting %v ..." , StartCommandWait )
64+ time .Sleep (StartCommandWait )
65+
66+ log .Debug ("Returning result while command still running" )
67+ return sb .String (), nil
68+ }
69+
70+ // run command with tty support and wait for stop
2571func RunCommand (log * logrus.Entry , commandName string , arg ... string ) (string , error ) {
26- cmdStr := path .Join ("commands" , commandName )
27- log .WithFields (logrus.Fields {"cmd" : cmdStr , "arg" : arg }).Info ("running command" )
72+ log .WithFields (logrus.Fields {"cmd" : commandName , "arg" : arg }).Info ("Running command" )
2873
29- log .Print ("Executing command..." )
30- cmd := exec .Command (cmdStr , arg ... )
74+ cmd := exec .Command (commandName , arg ... )
3175 cmd .Env = append (cmd .Environ (), "isE2E=true" )
3276
3377 outPipe , _ := cmd .StdoutPipe ()
3478 errPipe , _ := cmd .StderrPipe ()
3579
36- timer := time .AfterFunc (CommandTimeout , func () {
37- log .Print ("Terminating command..." )
80+ var sb strings.Builder
81+ go func (_ io.ReadCloser ) {
82+ reader := bufio .NewReader (errPipe )
83+ line , err := reader .ReadString ('\n' )
84+ for err == nil {
85+ sb .WriteString (line )
86+ line , err = reader .ReadString ('\n' )
87+ }
88+ }(errPipe )
89+
90+ go func (_ io.ReadCloser ) {
91+ reader := bufio .NewReader (outPipe )
92+ line , err := reader .ReadString ('\n' )
93+ for err == nil {
94+ sb .WriteString (line )
95+ line , err = reader .ReadString ('\n' )
96+ }
97+ }(outPipe )
98+
99+ log .Debug ("Starting ..." )
100+ _ , err := pty .Start (cmd )
101+ if err != nil {
102+ log .Errorf ("Start returned error: %v" , err )
103+ return "" , err
104+ }
105+
106+ log .Debug ("Waiting ..." )
107+ err = cmd .Wait ()
108+ if err != nil {
109+ log .Errorf ("Wait returned error: %v" , err )
110+ }
111+
112+ // TODO: find why this returns -1. That may be related to pty implementation
113+ /*if cmd.ProcessState.ExitCode() != 0 {
114+ return sb.String(), fmt.Errorf("Cmd returned code %d", cmd.ProcessState.ExitCode())
115+ }*/
116+
117+ return sb .String (), nil
118+ }
119+
120+ // run command with tty support and terminate it after timeout
121+ // it will also simulate a keyboard input during the run
122+ func RunCommandAndTerminate (log * logrus.Entry , commandName string , arg ... string ) (string , error ) {
123+ log .WithFields (logrus.Fields {"cmd" : commandName , "arg" : arg }).Info ("Running command and terminate" )
124+
125+ cmd := exec .Command (commandName , arg ... )
126+ cmd .Env = append (cmd .Environ (), "isE2E=true" )
127+
128+ outPipe , _ := cmd .StdoutPipe ()
129+ errPipe , _ := cmd .StderrPipe ()
130+
131+ timer := time .AfterFunc (RunCommandTimeout , func () {
132+ log .Debug ("Terminating command..." )
38133 err := cmd .Process .Signal (syscall .SIGTERM )
39134 if err != nil {
40135 log .Error (err )
@@ -61,23 +156,32 @@ func RunCommand(log *logrus.Entry, commandName string, arg ...string) (string, e
61156 }
62157 }(outPipe )
63158
159+ log .Debug ("Starting ..." )
64160 in , err := pty .Start (cmd )
65161 if err != nil {
66- panic (err )
162+ log .Errorf ("Start returned error: %v" , err )
163+ return "" , err
67164 }
68165
69166 timer = time .AfterFunc (30 * time .Second , func () {
70- log .Print ("Simulating keyboard typing..." )
167+ log .Debug ("Simulating keyboard typing..." )
71168 _ , err := in .Write ([]byte ("netobserv" ))
72169 if err != nil {
73170 log .Error (err )
74171 }
75172 })
76173 defer timer .Stop ()
77174
78- if err := cmd .Wait (); err != nil {
79- return sb .String (), err
175+ log .Debug ("Waiting ..." )
176+ err = cmd .Wait ()
177+ if err != nil {
178+ log .Errorf ("Wait returned error: %v" , err )
80179 }
81180
181+ // TODO: find why this returns -1. That may be related to pty implementation
182+ /*if cmd.ProcessState.ExitCode() != 0 {
183+ return sb.String(), fmt.Errorf("Cmd returned code %d", cmd.ProcessState.ExitCode())
184+ }*/
185+
82186 return sb .String (), nil
83187}
0 commit comments