func localhost() *henchman.Machine { tc := make(henchman.TransportConfig) local, _ := henchman.NewLocal(&tc) localhost := henchman.Machine{} localhost.Hostname = "127.0.0.1" localhost.Transport = local return &localhost }
func main() { username := flag.String("user", currentUsername().Username, "User to run as") usePassword := flag.Bool("password", false, "Use password authentication") keyfile := flag.String("private-keyfile", defaultKeyFile(), "Path to the keyfile") extraArgs := flag.String("args", "", "Extra arguments for the plan") modulesDir, err := validateModulesPath() if err != nil { log.Fatalf("Couldn't stat modules path '%s'\n", modulesDir) } flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [args] <plan>\n\n", os.Args[0]) flag.PrintDefaults() } flag.Parse() planFile := flag.Arg(0) if planFile == "" { flag.Usage() os.Exit(1) } if *username == "" { fmt.Fprintf(os.Stderr, "Missing username") os.Exit(1) } // We support two SSH authentications methods for now // password and client key bases. Both are mutually exclusive and password takes // higher precedence tc := make(henchman.TransportConfig) tc["username"] = *username if *usePassword { var password string if password, err = gopass.GetPass("Password:"******"Couldn't get password: "******"password"] = password } else { tc["keyfile"] = *keyfile } planBuf, err := ioutil.ReadFile(planFile) if err != nil { log.Fatalf("Error reading plan - %s\n", planFile) } var plan *henchman.Plan parsedArgs := parseExtraArgs(*extraArgs) plan, err = henchman.NewPlanFromYAML(planBuf, &parsedArgs) if err != nil { log.Fatalf("Couldn't read the plan: %s", err) os.Exit(1) } local := localhost() // Execute the same plan concurrently across all the machines. // Note the tasks themselves in plan are executed sequentially. wg := new(sync.WaitGroup) for _, hostname := range plan.Hosts { machine := henchman.Machine{} machine.Hostname = hostname machine.Transport = sshTransport(&tc, hostname) wg.Add(1) go func(machine *henchman.Machine) { defer wg.Done() for _, task := range plan.Tasks { var status *henchman.TaskStatus var err error if task.LocalAction { log.Printf("Local action detected\n") status, err = task.Run(local, plan.Vars) } else { status, err = task.Run(machine, plan.Vars) } plan.SaveStatus(&task, status.Status) if err != nil { log.Printf("Error when executing task: %s\n", err.Error()) } if status.Status == "failure" { log.Printf("Task was unsuccessful: %s\n", task.Id) break } } }(&machine) } wg.Wait() plan.PrintReport() }