7
7
"strings"
8
8
"time"
9
9
10
- "github.com/akerl/voyager/v2/travel"
10
+ "github.com/akerl/voyager/v3/cartogram"
11
+ "github.com/akerl/voyager/v3/travel"
11
12
12
13
"github.com/akerl/speculate/v2/creds"
13
14
"github.com/akerl/timber/v2/log"
@@ -25,28 +26,38 @@ type Processor struct {
25
26
RoleNames []string
26
27
ProfileNames []string
27
28
SkipConfirm bool
29
+ KeyFunc func (cartogram.Account ) (string , cartogram.Tags )
30
+ }
31
+
32
+ // ExecResult is based on creds.ExecResult but adds account tags
33
+ type ExecResult struct {
34
+ Tags cartogram.Tags `json:"tags"`
35
+ Error error `json:"error"`
36
+ ExitCode int `json:"exitcode"`
37
+ StdOut string `json:"stdout"`
38
+ StdErr string `json:"stderr"`
28
39
}
29
40
30
41
// ExecString runs a command string against a set of accounts
31
- func (p Processor ) ExecString (cmd string ) (map [string ]creds. ExecResult , error ) {
42
+ func (p Processor ) ExecString (cmd string ) (map [string ]ExecResult , error ) {
32
43
args , err := creds .StringToCommand (cmd )
33
44
if err != nil {
34
- return map [string ]creds. ExecResult {}, err
45
+ return map [string ]ExecResult {}, err
35
46
}
36
47
return p .Exec (args )
37
48
}
38
49
39
50
// Exec runs a command against a set of accounts
40
- func (p Processor ) Exec (cmd []string ) (map [string ]creds. ExecResult , error ) {
51
+ func (p Processor ) Exec (cmd []string ) (map [string ]ExecResult , error ) {
41
52
logger .InfoMsgf ("processing command: %v" , cmd )
42
53
43
54
paths , err := p .Grapher .ResolveAll (p .Args , p .RoleNames , p .ProfileNames )
44
55
if err != nil {
45
- return map [string ]creds. ExecResult {}, err
56
+ return map [string ]ExecResult {}, err
46
57
}
47
58
48
59
if ! p .confirm (paths ) {
49
- return map [string ]creds. ExecResult {}, fmt .Errorf ("aborted by user" )
60
+ return map [string ]ExecResult {}, fmt .Errorf ("aborted by user" )
50
61
}
51
62
52
63
inputCh := make (chan workerInput , len (paths ))
@@ -58,10 +69,15 @@ func (p Processor) Exec(cmd []string) (map[string]creds.ExecResult, error) {
58
69
}
59
70
60
71
for _ , item := range paths {
72
+ account := item [len (item )- 1 ]
73
+ key , tags := p .ParseKey (account .Account )
74
+
61
75
inputCh <- workerInput {
62
76
Path : item ,
63
77
Options : p .Options ,
64
78
Command : cmd ,
79
+ Key : key ,
80
+ Tags : tags ,
65
81
}
66
82
}
67
83
close (inputCh )
@@ -80,10 +96,10 @@ func (p Processor) Exec(cmd []string) (map[string]creds.ExecResult, error) {
80
96
),
81
97
)
82
98
83
- output := map [string ]creds. ExecResult {}
99
+ output := map [string ]ExecResult {}
84
100
for i := 1 ; i <= len (paths ); i ++ {
85
101
result := <- outputCh
86
- output [result .AccountID ] = result .ExecResult
102
+ output [result .Key ] = result .ExecResult
87
103
bar .Increment ()
88
104
refreshCh <- time .Now ()
89
105
}
@@ -92,13 +108,26 @@ func (p Processor) Exec(cmd []string) (map[string]creds.ExecResult, error) {
92
108
return output , nil
93
109
}
94
110
111
+ // ParseKey derives an output key from an account
112
+ func (p Processor ) ParseKey (account cartogram.Account ) (string , cartogram.Tags ) {
113
+ if p .KeyFunc == nil {
114
+ return DefaultKeyFunc (account )
115
+ }
116
+ return p .KeyFunc (account )
117
+ }
118
+
119
+ // DefaultKeyFunc uses the account's ID as the key, and passes through its tags
120
+ func DefaultKeyFunc (account cartogram.Account ) (string , cartogram.Tags ) {
121
+ return account .Account , account .Tags
122
+ }
123
+
95
124
func (p Processor ) confirm (paths []travel.Path ) bool {
96
125
if p .SkipConfirm {
97
126
return true
98
127
}
99
128
fmt .Fprintln (os .Stderr , "Will run on the following accounts:" )
100
129
for _ , item := range paths {
101
- accountID := item [len (item )- 1 ].Account
130
+ accountID := item [len (item )- 1 ].Account . Account
102
131
ok , account := p .Grapher .Pack .Lookup (accountID )
103
132
if ! ok {
104
133
fmt .Fprintf (os .Stderr , "Failed account lookup: %s\n " , accountID )
@@ -124,28 +153,32 @@ type workerInput struct {
124
153
Path travel.Path
125
154
Options travel.TraverseOptions
126
155
Command []string
156
+ Key string
157
+ Tags cartogram.Tags
127
158
}
128
159
129
160
type workerOutput struct {
130
- AccountID string
131
- ExecResult creds. ExecResult
161
+ Key string
162
+ ExecResult ExecResult
132
163
}
133
164
134
165
func execWorker (inputCh <- chan workerInput , outputCh chan <- workerOutput ) {
135
166
for item := range inputCh {
136
167
c , err := item .Path .TraverseWithOptions (item .Options )
137
168
if err != nil {
138
- outputCh <- workerOutput {ExecResult : creds.ExecResult {Error : err }}
139
- continue
140
- }
141
- accountID , err := c .AccountID ()
142
- if err != nil {
143
- outputCh <- workerOutput {ExecResult : creds.ExecResult {Error : err }}
169
+ outputCh <- workerOutput {ExecResult : ExecResult {Error : err }}
144
170
continue
145
171
}
172
+ result := c .Exec (item .Command )
146
173
outputCh <- workerOutput {
147
- AccountID : accountID ,
148
- ExecResult : c .Exec (item .Command ),
174
+ Key : item .Key ,
175
+ ExecResult : ExecResult {
176
+ Tags : item .Tags ,
177
+ Error : result .Error ,
178
+ ExitCode : result .ExitCode ,
179
+ StdOut : result .StdOut ,
180
+ StdErr : result .StdErr ,
181
+ },
149
182
}
150
183
}
151
184
}
0 commit comments