6
6
"errors"
7
7
"fmt"
8
8
"log"
9
- "sort"
10
9
"strings"
11
10
"sync"
12
11
"time"
@@ -19,6 +18,7 @@ import (
19
18
wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
20
19
"github.com/argoproj/argo-workflows/v3/pkg/plugins/executor"
21
20
"github.com/argoproj/gitops-engine/pkg/sync/hook"
21
+ "gopkg.in/yaml.v3"
22
22
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
23
23
"k8s.io/utils/pointer"
24
24
@@ -49,149 +49,89 @@ func (e *ApiExecutor) Execute(args executor.ExecuteTemplateArgs) executor.Execut
49
49
return errorResponse (err )
50
50
}
51
51
52
- totalActionGroups := len (plugin .ArgoCD .Actions )
53
- actionGroupCount := 0
54
-
55
- var groupOutputs [][]any
56
- for i , actionGroup := range plugin .ArgoCD .Actions {
57
- outputs , err := e .runActionsParallel (actionGroup )
58
- if err != nil {
59
- return failedResponse (wfv1 .Progress (fmt .Sprintf ("%d/%d" , actionGroupCount , totalActionGroups )), fmt .Errorf ("action group %d of %d failed: %w" , i + 1 , totalActionGroups , err ))
60
- }
61
- groupOutputs = append (groupOutputs , outputs )
62
- actionGroupCount += 1
63
- }
64
-
65
- outputsJson , err := json .Marshal (groupOutputs )
52
+ output , err := e .runAction (plugin .ArgoCD )
66
53
if err != nil {
67
- err = fmt .Errorf ("failed to marshal outputs to JSON: %w" , err )
68
- log .Println (err .Error ())
69
- return errorResponse (err )
54
+ return failedResponse (wfv1 .Progress (fmt .Sprintf ("0/1" )), fmt .Errorf ("action failed: %w" , err ))
70
55
}
71
56
72
- outputsJsonAnyString := wfv1 .AnyString (outputsJson )
73
-
74
57
return executor.ExecuteTemplateReply {
75
58
Node : & wfv1.NodeResult {
76
59
Phase : wfv1 .NodeSucceeded ,
77
- Message : "Actions completed" ,
78
- Progress : wfv1 . Progress ( fmt . Sprintf ( "%d/%d" , actionGroupCount , totalActionGroups )) ,
60
+ Message : "Action completed" ,
61
+ Progress : "1/1" ,
79
62
Outputs : & wfv1.Outputs {
80
- Parameters : []wfv1.Parameter {
81
- {
82
- Name : "outputs" ,
83
- Value : & outputsJsonAnyString ,
84
- },
85
- },
63
+ Result : pointer .String (output ),
86
64
},
87
65
},
88
66
}
89
67
}
90
68
91
- type actionResult struct {
92
- index int
93
- err error
94
- output any
95
- }
96
-
97
- // runActionsParallel runs the given group of actions in parallel and returns aggregated errors, if any.
98
- func (e * ApiExecutor ) runActionsParallel (actionGroup []ActionSpec ) ([]any , error ) {
69
+ // runAction runs the given action and returns outputs or errors, if any.
70
+ func (e * ApiExecutor ) runAction (action ActionSpec ) (out string , err error ) {
99
71
closer , appClient , err := e .apiClient .NewApplicationClient ()
100
72
if err != nil {
101
- return nil , fmt .Errorf ("failed to initialize Application API client: %w" , err )
73
+ return "" , fmt .Errorf ("failed to initialize Application API client: %w" , err )
102
74
}
103
75
defer io .Close (closer )
104
76
105
77
closer , settingsClient , err := e .apiClient .NewSettingsClient ()
106
78
if err != nil {
107
- return nil , fmt .Errorf ("failed to initialize Application API client: %w" , err )
79
+ return "" , fmt .Errorf ("failed to initialize Application API client: %w" , err )
108
80
}
109
81
defer io .Close (closer )
110
82
111
- wg := sync.WaitGroup {}
112
- actionResults := make (chan actionResult , len (actionGroup ))
113
- for i , action := range actionGroup {
114
- i := i
115
- action := action
116
- if action .App == nil {
117
- return nil , fmt .Errorf ("action %d of %d is missing a valid action type (sync or diff)" , i + 1 , len (actionGroup ))
118
- }
119
- if action .App .Sync != nil && action .App .Diff != nil {
120
- return nil , fmt .Errorf ("action %d of %d has both multiple types of actions defined" , i + 1 , len (actionGroup ))
121
- }
122
- if action .App .Sync == nil && action .App .Diff == nil {
123
- return nil , fmt .Errorf ("action %d of %d has no action defined" , i + 1 , len (actionGroup ))
124
- }
125
- wg .Add (1 )
126
- go func (actionNum int ) {
127
- defer wg .Done ()
128
- if action .App .Sync != nil {
129
- err := syncAppsParallel (* action .App .Sync , action .Timeout , appClient )
130
- if err != nil {
131
- actionResults <- actionResult {index : i , err : fmt .Errorf ("parallel item %d of %d failed: failed to sync Application(s): %w" , actionNum + 1 , len (actionGroup ), err )}
132
- } else {
133
- actionResults <- actionResult {index : i , output : "" }
134
- }
135
- }
136
- if action .App .Diff != nil {
137
- diff , err := diffApp (* action .App .Diff , action .Timeout , appClient , settingsClient )
138
- if err != nil {
139
- actionResults <- actionResult {index : i , err : fmt .Errorf ("parallel item %d of %d failed: failed to diff Application: %w" , actionNum + 1 , len (actionGroup ), err )}
140
- } else {
141
- actionResults <- actionResult {index : i , output : diff }
142
- }
143
- }
144
- }(i )
83
+ if action .App == nil {
84
+ return "" , errors .New ("action is missing a valid action type (i.e. an 'app' block)" )
145
85
}
146
- go func () {
147
- wg .Wait ()
148
- close (actionResults )
149
- }()
150
- var results []actionResult
151
- for out := range actionResults {
152
- results = append (results , out )
86
+ if action .App .Sync != nil && action .App .Diff != nil {
87
+ return "" , errors .New ("action has multiple types of action defined (both sync and diff)" )
153
88
}
154
- sort .Slice (results , func (i , j int ) bool {
155
- return results [i ].index < results [j ].index
156
- })
157
- hasError := false
158
- var errorMessages []string
159
- var outputs []any
160
- for _ , result := range results {
161
- if result .err != nil {
162
- hasError = true
163
- errorMessages = append (errorMessages , result .err .Error ())
164
- outputs = append (outputs , nil )
165
- } else {
166
- errorMessages = append (errorMessages , "" )
167
- outputs = append (outputs , result .output )
89
+ if action .App .Sync == nil && action .App .Diff == nil {
90
+ return "" , errors .New ("app action has no action type specified (must be sync or diff)" )
91
+ }
92
+
93
+ if action .App .Sync != nil {
94
+ err = syncAppsParallel (* action .App .Sync , action .Timeout , appClient )
95
+ if err != nil {
168
96
}
169
97
}
170
- if hasError {
171
- return nil , fmt .Errorf ("one or more actions failed: %s" , strings .Join (errorMessages , "; " ))
98
+ if action .App .Diff != nil {
99
+ out , err = diffApp (* action .App .Diff , action .Timeout , appClient , settingsClient )
100
+ if err != nil {
101
+ }
172
102
}
173
- return outputs , nil
103
+ return out , err
174
104
}
175
105
176
106
// syncAppsParallel loops over the apps in a SyncAction and syncs them in parallel. It waits for all responses and then
177
107
// aggregates any errors.
178
108
func syncAppsParallel (action SyncAction , timeout string , appClient application.ApplicationServiceClient ) error {
109
+ var apps []App
110
+ err := yaml .Unmarshal ([]byte (action .Apps ), & apps )
111
+ if err != nil {
112
+ return fmt .Errorf ("failed to unmarshal apps: %w" , err )
113
+ }
114
+ var options []string
115
+ err = yaml .Unmarshal ([]byte (action .Options ), & options )
116
+ if err != nil {
117
+ return fmt .Errorf ("failed to unmarshal options: %w" , err )
118
+ }
179
119
ctx , cancel , err := durationStringToContext (timeout )
180
120
if err != nil {
181
121
return fmt .Errorf ("failed get action context: %w" , err )
182
122
}
183
123
defer cancel ()
184
124
wg := sync.WaitGroup {}
185
125
errChan := make (chan error , len (action .Apps ))
186
- for _ , app := range action . Apps {
126
+ for _ , app := range apps {
187
127
app := app
188
128
wg .Add (1 )
189
129
go func () {
190
130
defer wg .Done ()
191
131
_ , err := appClient .Sync (ctx , & application.ApplicationSyncRequest {
192
132
Name : pointer .String (app .Name ),
193
133
AppNamespace : pointer .String (app .Namespace ),
194
- SyncOptions : & application.SyncOptions {Items : action . Options },
134
+ SyncOptions : & application.SyncOptions {Items : options },
195
135
})
196
136
if err != nil {
197
137
errChan <- fmt .Errorf ("failed to sync app %q: %w" , app .Name , err )
@@ -308,7 +248,7 @@ func diffApp(action DiffAction, timeout string, appClient application.Applicatio
308
248
target = item .target
309
249
}
310
250
311
- diff , err = GetDiff (action . App . Name , live , target )
251
+ diff , err = GetDiff (live , target )
312
252
if err != nil {
313
253
return "" , fmt .Errorf ("failed to get diff: %w" , err )
314
254
}
0 commit comments