-
Notifications
You must be signed in to change notification settings - Fork 51
/
remote_execution.go
118 lines (94 loc) · 1.99 KB
/
remote_execution.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
import (
"fmt"
"io"
"reflect"
"github.com/reconquest/hierr-go"
)
type remoteExecution struct {
stdin io.WriteCloser
nodes map[*distributedLockNode]*remoteExecutionNode
}
type remoteExecutionResult struct {
node *remoteExecutionNode
err error
}
func (execution *remoteExecution) wait() error {
tracef(`waiting %d nodes to finish`, len(execution.nodes))
results := make(chan *remoteExecutionResult, 0)
for _, node := range execution.nodes {
go func(node *remoteExecutionNode) {
results <- &remoteExecutionResult{node, node.wait()}
}(node)
}
executionErrors := fmt.Errorf(
`commands are exited with non-zero code`,
)
var (
status = &struct {
Phase string
Total int
Fails int
Success int
}{
Phase: `wait`,
Total: len(execution.nodes),
}
exitCodes = map[int]int{}
)
setStatus(status)
for range execution.nodes {
result := <-results
if result.err != nil {
exitCodes[result.node.exitCode]++
executionErrors = hierr.Push(
executionErrors,
hierr.Errorf(
result.err,
`%s has finished with error`,
result.node.node.String(),
),
)
status.Fails++
status.Total--
tracef(
`%s finished with exit code: '%d'`,
result.node.node.String(),
result.node.exitCode,
)
continue
}
status.Success++
tracef(
`%s has successfully finished execution`,
result.node.node.String(),
)
}
if status.Fails > 0 {
if status.Fails == len(execution.nodes) {
exitCodesValue := reflect.ValueOf(exitCodes)
topError := fmt.Errorf(
`commands are failed on all %d nodes`,
len(execution.nodes),
)
for _, key := range exitCodesValue.MapKeys() {
topError = hierr.Push(
topError,
fmt.Sprintf(
`code %d (%d nodes)`,
key.Int(),
exitCodesValue.MapIndex(key).Int(),
),
)
}
return topError
}
return hierr.Errorf(
executionErrors,
`commands are failed on %d out of %d nodes`,
status.Fails,
len(execution.nodes),
)
}
return nil
}