2020-11-21 19:36:13 -05:00
|
|
|
package common
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"runtime"
|
|
|
|
|
"sync"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ParallelCommand is a type that declares functions
|
|
|
|
|
// the ps plugins can execute in parallel
|
|
|
|
|
type ParallelCommand func(string) error
|
|
|
|
|
|
|
|
|
|
// ParallelCommandResult is the result of a parallel
|
|
|
|
|
// command run
|
|
|
|
|
type ParallelCommandResult struct {
|
2020-12-19 18:24:09 -05:00
|
|
|
Name string
|
|
|
|
|
CommandName string
|
|
|
|
|
Error error
|
2020-11-21 19:36:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RunCommandAgainstAllApps runs a given ParallelCommand against all apps
|
|
|
|
|
func RunCommandAgainstAllApps(command ParallelCommand, commandName string, parallelCount int) error {
|
|
|
|
|
runInSerial := false
|
|
|
|
|
|
|
|
|
|
if parallelCount < -1 {
|
|
|
|
|
return fmt.Errorf("Invalid value %d for --parallel flag", parallelCount)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if parallelCount == -1 {
|
|
|
|
|
cpuCount := runtime.NumCPU()
|
|
|
|
|
LogWarn(fmt.Sprintf("Setting --parallel=%d value to CPU count of %d", parallelCount, cpuCount))
|
|
|
|
|
parallelCount = cpuCount
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if parallelCount == 0 || parallelCount == 1 {
|
|
|
|
|
LogWarn(fmt.Sprintf("Running %s in serial mode", commandName))
|
|
|
|
|
runInSerial = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if runInSerial {
|
2020-11-21 23:55:03 -05:00
|
|
|
return RunCommandAgainstAllAppsSerially(command, commandName)
|
2020-11-21 19:36:13 -05:00
|
|
|
}
|
|
|
|
|
|
2020-11-21 23:55:03 -05:00
|
|
|
return RunCommandAgainstAllAppsInParallel(command, commandName, parallelCount)
|
2020-11-21 19:36:13 -05:00
|
|
|
}
|
|
|
|
|
|
2020-11-21 23:56:42 -05:00
|
|
|
// RunCommandAgainstAllAppsInParallel runs a given ParallelCommand against all apps in parallel
|
2020-11-21 23:55:03 -05:00
|
|
|
func RunCommandAgainstAllAppsInParallel(command ParallelCommand, commandName string, parallelCount int) error {
|
2020-11-21 19:36:13 -05:00
|
|
|
apps, err := DokkuApps()
|
|
|
|
|
if err != nil {
|
|
|
|
|
LogWarn(err.Error())
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jobs := make(chan string, parallelCount)
|
|
|
|
|
results := make(chan ParallelCommandResult, len(apps))
|
|
|
|
|
|
|
|
|
|
go allocateJobs(apps, jobs)
|
|
|
|
|
done := make(chan error)
|
|
|
|
|
go aggregateResults(results, done)
|
2020-12-19 18:24:09 -05:00
|
|
|
createParallelWorkerPool(jobs, results, command, commandName, parallelCount)
|
2020-11-21 19:36:13 -05:00
|
|
|
err = <-done
|
|
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 23:56:42 -05:00
|
|
|
// RunCommandAgainstAllAppsSerially runs a given ParallelCommand against all apps serially
|
2020-11-21 23:55:03 -05:00
|
|
|
func RunCommandAgainstAllAppsSerially(command ParallelCommand, commandName string) error {
|
2020-11-21 19:36:13 -05:00
|
|
|
apps, err := DokkuApps()
|
|
|
|
|
if err != nil {
|
|
|
|
|
LogWarn(err.Error())
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errorCount := 0
|
|
|
|
|
for _, appName := range apps {
|
|
|
|
|
LogInfo1(fmt.Sprintf("Running %s against app %s", commandName, appName))
|
|
|
|
|
if err = command(appName); err != nil {
|
2020-12-19 18:24:09 -05:00
|
|
|
LogWarn(fmt.Sprintf("Error running %s against app %s: %s", commandName, appName, err.Error()))
|
2020-11-21 19:36:13 -05:00
|
|
|
errorCount++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if errorCount > 0 {
|
|
|
|
|
return fmt.Errorf("%s command returned %d errors", commandName, errorCount)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func allocateJobs(input []string, jobs chan string) {
|
|
|
|
|
for _, job := range input {
|
|
|
|
|
jobs <- job
|
|
|
|
|
}
|
|
|
|
|
close(jobs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func aggregateResults(results chan ParallelCommandResult, done chan error) {
|
|
|
|
|
var parallelError error
|
|
|
|
|
errorCount := 0
|
|
|
|
|
for result := range results {
|
|
|
|
|
if result.Error != nil {
|
2020-12-19 18:24:09 -05:00
|
|
|
LogWarn(fmt.Sprintf("Error running %s against %s: %s", result.CommandName, result.Name, result.Error.Error()))
|
2020-11-21 19:36:13 -05:00
|
|
|
errorCount++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if errorCount > 0 {
|
|
|
|
|
parallelError = fmt.Errorf("Encountered %d errors during parallel run", errorCount)
|
|
|
|
|
}
|
|
|
|
|
done <- parallelError
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-19 18:24:09 -05:00
|
|
|
func createParallelWorker(jobs chan string, results chan ParallelCommandResult, command ParallelCommand, commandName string, wg *sync.WaitGroup, workerID int) {
|
2020-11-21 19:36:13 -05:00
|
|
|
for job := range jobs {
|
|
|
|
|
LogInfo1(fmt.Sprintf("Running command against %s", job))
|
|
|
|
|
output := ParallelCommandResult{
|
2020-12-19 18:24:09 -05:00
|
|
|
Name: job,
|
|
|
|
|
CommandName: commandName,
|
|
|
|
|
Error: command(job),
|
2020-11-21 19:36:13 -05:00
|
|
|
}
|
|
|
|
|
results <- output
|
|
|
|
|
}
|
|
|
|
|
wg.Done()
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-19 18:24:09 -05:00
|
|
|
func createParallelWorkerPool(jobs chan string, results chan ParallelCommandResult, command ParallelCommand, commandName string, numberOfWorkers int) {
|
2020-11-21 19:36:13 -05:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
for i := 0; i < numberOfWorkers; i++ {
|
|
|
|
|
wg.Add(1)
|
2020-12-19 18:24:09 -05:00
|
|
|
go createParallelWorker(jobs, results, command, commandName, &wg, i)
|
2020-11-21 19:36:13 -05:00
|
|
|
}
|
|
|
|
|
wg.Wait()
|
|
|
|
|
close(results)
|
|
|
|
|
}
|