From 2f246bb05c82d02eb3f84ffbca5ca5983ff70a03 Mon Sep 17 00:00:00 2001 From: Quentin Date: Thu, 23 Sep 2021 16:40:41 +0200 Subject: [PATCH] WIP safer logs --- main.go | 69 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/main.go b/main.go index 9b21025..90ed679 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main import ( - "bytes" + "bufio" "io" "net" "os" @@ -21,11 +21,19 @@ import ( const PARALLELIZE = 16 const instanceNotFound = Error("instance not found") +var msgOut chan string +var msgErr chan string + func main() { if len(os.Args) < 2 { usage() } + msgOut = make(chan string, PARALLELIZE) + msgErr = make(chan string, PARALLELIZE) + go logger(os.Stdout, msgOut) + go logger(os.Stderr, msgErr) + var err error switch os.Args[1] { case "spawn": @@ -37,17 +45,23 @@ func main() { } if err != nil { - fmt.Fprintf(os.Stderr, "cmd failed: %v\n", err) + msgErr <- fmt.Sprintf("cmd failed: %v\n", err) os.Exit(1) } } +func logger(o *os.File, c chan string) { + for m := range c { + fmt.Fprint(o, m) + } +} + func usage() { var programName = "swtool" if len(os.Args) > 0 { programName = os.Args[0] } - fmt.Fprintf(os.Stderr, "Usage: %v (spawn|run|destroy)\n", programName) + msgErr <- fmt.Sprintf("Usage: %v (spawn|run|destroy)\n", programName) os.Exit(1) } @@ -70,6 +84,7 @@ type instanceReceiver interface { func passInstanceTo(r io.Reader, d instanceReceiver) error { com := make(chan error, PARALLELIZE) + count := 0 failed := 0 @@ -87,14 +102,15 @@ func passInstanceTo(r io.Reader, d instanceReceiver) error { go func(zone, machine, image, name string) { err := d.onInstance(zone, machine, image, name) if err != nil { - fmt.Fprintf(os.Stderr, "❌ Operation failed for %v (%v, %v, %v): %v\n", name, zone, machine, image, err) + msgErr <- fmt.Sprintf("❌ Operation failed for %v (%v, %v, %v): %v\n", name, zone, machine, image, err) } com <- err }(zone, machine, image, name) + count += 1 } - fmt.Fprintf(os.Stdout, "ℹ️ Waiting for %v servers\n", count) + msgOut <- fmt.Sprintf("ℹ️ Waiting for %v servers\n", count) for count > 0 { err := <- com count -= 1 @@ -170,7 +186,7 @@ func (sp *spawner) onInstance(zone, machine, image, name string) error { if err == nil { ip := parseIP(targetServer) if targetServer.State == instance.ServerStateRunning { - fmt.Fprintf(os.Stdout, "🟣 Found %v on zone %v with ip %v\n", targetServer.Name, targetServer.Zone, ip) + msgOut <- fmt.Sprintf("🟣 Found %v on zone %v with ip %v\n", targetServer.Name, targetServer.Zone, ip) return nil } } else if err == instanceNotFound { @@ -207,7 +223,7 @@ func (sp *spawner) onInstance(zone, machine, image, name string) error { } ip := parseIP(targetServer) - fmt.Fprintf(os.Stdout, "✅ Started %v on zone %v with ip %v\n", targetServer.Name, targetServer.Zone, ip) + msgOut <- fmt.Sprintf("✅ Started %v on zone %v with ip %v\n", targetServer.Name, targetServer.Zone, ip) return nil } @@ -224,7 +240,7 @@ func (dt *destroyer) onInstance(zone, machine, image, name string) error { targetServer, err := dt.getInstanceByName(z, name) if err == instanceNotFound { - fmt.Fprintf(os.Stdout, "🟣 %v is already destroyed\n", name) + msgOut <- fmt.Sprintf("🟣 %v is already destroyed\n", name) return nil } else if err != nil { return err @@ -248,7 +264,7 @@ func (dt *destroyer) onInstance(zone, machine, image, name string) error { } ip := parseIP(targetServer) - fmt.Fprintf(os.Stdout, "✅ Destroyed %v on zone %v with ip %v\n", targetServer.Name, targetServer.Zone, ip) + msgOut <- fmt.Sprintf("✅ Destroyed %v on zone %v with ip %v\n", targetServer.Name, targetServer.Zone, ip) return nil } @@ -296,7 +312,7 @@ func (r *runner) connect(zone, name string) (*ssh.Client, error) { func (r *runner) send(sshClient *ssh.Client) error { // Source script if len(os.Args) < 3 { - return errors.New("Missing script to run on the command line") + return errors.New("missing script to run on the command line") } src, err := os.Open(os.Args[2]) @@ -327,6 +343,16 @@ func (r *runner) send(sshClient *ssh.Client) error { return err } +func readerToChan(r io.Reader, c chan string) { + br := bufio.NewReader(r) + for { + s, err := br.ReadString('\n') + if err != nil { + break + } + c <- s + } +} func (r *runner) exec(sshClient *ssh.Client) error { // Run the script session, err := sshClient.NewSession() @@ -335,16 +361,21 @@ func (r *runner) exec(sshClient *ssh.Client) error { } defer session.Close() - var sshStdout, sshStderr bytes.Buffer - session.Stdout = &sshStdout - session.Stderr = &sshStderr + if os.Getenv("VERBOSE") != "" { + readErr, err := session.StderrPipe() + if err != nil { + return err + } + readerToChan(readErr, msgErr) + + readOut, err := session.StdoutPipe() + if err != nil { + return err + } + readerToChan(readOut, msgOut) + } err = session.Run("/tmp/nuage") - if os.Getenv("VERBOSE") != "" { - fmt.Fprintf(os.Stdout, "logs\n") - io.Copy(os.Stdout, &sshStdout) - io.Copy(os.Stderr, &sshStderr) - } if err != nil { return err } @@ -369,7 +400,7 @@ func (r *runner) onInstance(zone, machine, image, name string) error { return err } - fmt.Fprintf(os.Stdout, "✅ Successfully ran the script on %v (zone %v)\n", name, zone) + msgOut <- fmt.Sprintf("✅ Successfully ran the script on %v (zone %v)\n", name, zone) return nil }