Example #1
0
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
}
Example #2
0
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")
	hostsFile := flag.String("i", "", "Specify hosts file name")

	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 hostsFileBuf []byte = nil
	if *hostsFile != "" {
		hostsFileBuf, err = ioutil.ReadFile(*hostsFile)
		if err != nil {
			log.Fatalf("Error reading hosts file - %s\n", *hostsFile)
		}
	}

	var plan *henchman.Plan
	parsedArgs := parseExtraArgs(*extraArgs)
	plan, err = henchman.NewPlanFromYAML(planBuf, hostsFileBuf, parsedArgs)
	if err != nil {
		log.Fatalf("Couldn't read the plan: %s", err)
		os.Exit(1)
	}

	fmt.Println(plan.Tasks)
	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)

		// initializes a map for "register" values for each host
		registerMap := make(map[string]interface{})

		//renders all tasks in the plan file
		tasks, err := henchman.PrepareTasks(plan.Tasks, plan.Vars, machine)
		fmt.Println("\n" + "INITIAL TASKS")
		fmt.Println(tasks)
		fmt.Println()
		if err != nil {
			fmt.Println(err)
		}

		// for each host use the task list of the plan and run each task individually
		wg.Add(1)
		go func(machine *henchman.Machine) {
			defer wg.Done()

			// makes a temporary tasks to temper with
			for ndx := 0; ndx < len(tasks); ndx++ {
				var status *henchman.TaskStatus
				var err error
				task := tasks[ndx]

				// if there is a valid include field within task
				//    update task list
				// else
				//    do standard task run procedure
				whenVal, err := task.ProcessWhen(registerMap)
				if err != nil {
					log.Println("Error at When Eval at task: " + task.Name)
					log.Println("Error: " + err.Error())
				}
				if whenVal == true {
					if task.Include != "" {
						tasks, err = henchman.UpdateTasks(tasks, task.Vars, ndx, *machine)
						fmt.Println("\n" + "NESTED TASKS at " + machine.Hostname)
						fmt.Println(tasks)
						fmt.Println()
						if err != nil {
							log.Println("Error at Include Eval at task: " + task.Name)
							log.Println("Error: " + err.Error())
						}
					} else {
						if tasks[ndx].LocalAction {
							log.Printf("Local action detected\n")
							status, err = task.Run(local, registerMap)
						} else {
							status, err = task.Run(machine, registerMap)
						}
						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()
}