Skip to content

Instantly share code, notes, and snippets.

@techjanitor
Created June 11, 2015 18:16
Show Gist options
  • Save techjanitor/052cc09f821016806dca to your computer and use it in GitHub Desktop.
Save techjanitor/052cc09f821016806dca to your computer and use it in GitHub Desktop.
concurrent exec: single producer, multiple consumer
package main
import (
"bufio"
"flag"
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
"sync"
)
func main() {
// Flags for output
commandFlag := flag.String("command", "", "what command to send to shell")
hostsFlag := flag.String("hosts", "", "the file with hosts")
conFlag := flag.Int("threads", 8, "level of concurrent operations")
// Parse flags
flag.Parse()
switch {
case *commandFlag == "":
fmt.Fprintln(os.Stderr, "command required")
os.Exit(1)
case *hostsFlag == "":
fmt.Fprintln(os.Stderr, "host file required")
os.Exit(1)
}
// initialize waitgroup
var wg sync.WaitGroup
// make channel for the commands
tasks := make(chan *exec.Cmd, 64)
// create buffer for output
out := bufio.NewWriter(os.Stdout)
// for loop that will make x routines set from threads flag
for i := 0; i < *conFlag; i++ {
wg.Add(1)
go func() {
// range through tasks channel
for cmd := range tasks {
// execute command and get output
cmdout, err := cmd.Output()
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
// print to buffer
fmt.Fprintf(out, "%s", cmdout)
out.Flush()
}
wg.Done()
}()
}
// read file
file, err := ioutil.ReadFile(*hostsFlag)
if err != nil {
fmt.Fprintln(os.Stderr, "problem opening file")
os.Exit(1)
}
// trim last newline from file
h := strings.TrimSpace(string(file))
// split on newlines into slice
hosts := strings.Split(h, "\n")
// range over hostnames in slice
for _, host := range hosts {
tasks <- exec.Command("mco", "shell", "--publish_timeout=2", "-t2", "-I", host, *commandFlag)
}
// close channel
close(tasks)
// wait until routines are done
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment