@@ -3,6 +3,7 @@ package service
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
+ "fmt"
6
7
"sync"
7
8
8
9
log "github.com/sirupsen/logrus"
@@ -16,8 +17,15 @@ import (
16
17
appclientset "github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned"
17
18
)
18
19
20
+ const (
21
+ CHANGE_REVISION_ANN = "mrp-controller.argoproj.io/change-revision"
22
+ CHANGE_REVISIONS_ANN = "mrp-controller.argoproj.io/change-revisions"
23
+ GIT_REVISION_ANN = "mrp-controller.argoproj.io/git-revision"
24
+ GIT_REVISIONS_ANN = "mrp-controller.argoproj.io/git-revisions"
25
+ )
26
+
19
27
type ACRService interface {
20
- ChangeRevision (ctx context.Context , application * application.Application ) error
28
+ ChangeRevision (ctx context.Context , application * application.Application , useAnnotations bool ) error
21
29
}
22
30
23
31
type acrService struct {
@@ -55,7 +63,7 @@ func getChangeRevision(app *application.Application) string {
55
63
return ""
56
64
}
57
65
58
- func (c * acrService ) ChangeRevision (ctx context.Context , a * application.Application ) error {
66
+ func (c * acrService ) ChangeRevision (ctx context.Context , a * application.Application , useAnnotations bool ) error {
59
67
c .lock .Lock ()
60
68
defer c .lock .Unlock ()
61
69
@@ -73,36 +81,108 @@ func (c *acrService) ChangeRevision(ctx context.Context, a *application.Applicat
73
81
return nil
74
82
}
75
83
76
- revision , err := c .calculateRevision (ctx , app )
84
+ currentRevision , previousRevision := c .getRevisions (ctx , a )
85
+ if currentRevision == "" {
86
+ c .logger .Infof ("Got empty current revision for application %s, is it an unsupported multisource or helm repo based application?" , app .Name )
87
+ return nil
88
+ }
89
+ revision , err := c .calculateRevision (ctx , app , currentRevision , previousRevision )
77
90
if err != nil {
78
91
return err
79
92
}
80
93
94
+ var revisions []string
81
95
if revision == nil || * revision == "" {
82
96
c .logger .Infof ("Revision for application %s is empty" , app .Name )
83
- return nil
97
+ } else {
98
+ c .logger .Infof ("Change revision for application %s is %s" , app .Name , * revision )
99
+ revisions = []string {* revision }
84
100
}
85
101
86
- c .logger .Infof ("Change revision for application %s is %s" , app .Name , * revision )
87
-
88
102
app , err = c .applicationClientset .ArgoprojV1alpha1 ().Applications (app .Namespace ).Get (ctx , app .Name , metav1.GetOptions {})
89
103
if err != nil {
90
104
return err
91
105
}
92
106
93
- revisions := [] string { * revision }
107
+ patchMap := make ( map [ string ] any , 2 )
94
108
95
- if app .Status .OperationState != nil && app .Status .OperationState .Operation .Sync != nil {
96
- c .logger .Infof ("Patch operation status for application %s" , app .Name )
97
- return c .patchOperationSyncResultWithChangeRevision (ctx , app , revisions )
109
+ if len (revisions ) > 0 {
110
+ if app .Status .OperationState != nil && app .Status .OperationState .Operation .Sync != nil {
111
+ c .logger .Infof ("Patch operation status for application %s" , app .Name )
112
+ patchMap = c .patchOperationSyncResultWithChangeRevision (revisions )
113
+ } else {
114
+ c .logger .Infof ("Patch operation for application %s" , app .Name )
115
+ patchMap = c .patchOperationWithChangeRevision (revisions )
116
+ }
98
117
}
118
+ if useAnnotations {
119
+ err = c .addAnnotationPatch (patchMap , app , * revision , revisions , currentRevision , []string {currentRevision })
120
+ if err != nil {
121
+ return err
122
+ }
123
+ }
124
+ if len (patchMap ) > 0 {
125
+ c .logger .Infof ("Patching resource: %v" , patchMap )
126
+ patch , err := json .Marshal (patchMap )
127
+ if err != nil {
128
+ return err
129
+ }
130
+ _ , err = c .applicationClientset .ArgoprojV1alpha1 ().Applications (a .Namespace ).Patch (ctx , a .Name , types .MergePatchType , patch , metav1.PatchOptions {})
131
+ return err
132
+ }
133
+ c .logger .Infof ("No patch needed" )
134
+ return nil
135
+ }
99
136
100
- c .logger .Infof ("Patch operation for application %s" , app .Name )
101
- return c .patchOperationWithChangeRevision (ctx , app , revisions )
137
+ func addPatchIfNeeded (annotations map [string ]string , currentAnnotations map [string ]string , key string , val string ) {
138
+ currentVal , ok := currentAnnotations [key ]
139
+ if ! ok || currentVal != val {
140
+ annotations [key ] = val
141
+ }
102
142
}
103
143
104
- func (c * acrService ) calculateRevision (ctx context.Context , a * application.Application ) (* string , error ) {
105
- currentRevision , previousRevision := c .getRevisions (ctx , a )
144
+ func (c * acrService ) addAnnotationPatch (m map [string ]any ,
145
+ a * application.Application ,
146
+ changeRevision string ,
147
+ changeRevisions []string ,
148
+ gitRevision string ,
149
+ gitRevisions []string ,
150
+ ) error {
151
+ c .logger .Infof ("annotating application '%s', changeRevision=%s, changeRevisions=%v, gitRevision=%s, gitRevisions=%v" , a .Name , changeRevision , changeRevisions , gitRevision , gitRevisions )
152
+ annotations := map [string ]string {}
153
+ currentAnnotations := a .Annotations
154
+
155
+ if changeRevision != "" {
156
+ addPatchIfNeeded (annotations , currentAnnotations , CHANGE_REVISION_ANN , changeRevision )
157
+ }
158
+ if len (changeRevisions ) > 0 {
159
+ changeRevisionsJSON , err := json .Marshal (changeRevisions )
160
+ if err != nil {
161
+ return fmt .Errorf ("failed to marshall changeRevisions %v: %w" , changeRevisions , err )
162
+ }
163
+ addPatchIfNeeded (annotations , currentAnnotations , CHANGE_REVISIONS_ANN , string (changeRevisionsJSON ))
164
+ }
165
+ if gitRevision != "" {
166
+ addPatchIfNeeded (annotations , currentAnnotations , GIT_REVISION_ANN , gitRevision )
167
+ }
168
+ if len (gitRevisions ) > 0 {
169
+ gitRevisionsJSON , err := json .Marshal (gitRevisions )
170
+ if err != nil {
171
+ return fmt .Errorf ("failed to marshall gitRevisions %v: %w" , gitRevisions , err )
172
+ }
173
+ addPatchIfNeeded (annotations , currentAnnotations , GIT_REVISIONS_ANN , string (gitRevisionsJSON ))
174
+ }
175
+
176
+ if len (annotations ) == 0 {
177
+ c .logger .Info ("no need to add annotations" )
178
+ } else {
179
+ c .logger .Infof ("added annotations to application %s patch: %v" , a .Name , annotations )
180
+ m ["metadata" ] = map [string ]any {"annotations" : annotations }
181
+ }
182
+ return nil
183
+ }
184
+
185
+ func (c * acrService ) calculateRevision (ctx context.Context , a * application.Application , currentRevision string , previousRevision string ) (* string , error ) {
106
186
c .logger .Infof ("Calculate revision for application '%s', current revision '%s', previous revision '%s'" , a .Name , currentRevision , previousRevision )
107
187
changeRevisionResult , err := c .applicationServiceClient .GetChangeRevision (ctx , & appclient.ChangeRevisionRequest {
108
188
AppName : ptr .To (a .GetName ()),
@@ -116,33 +196,28 @@ func (c *acrService) calculateRevision(ctx context.Context, a *application.Appli
116
196
return changeRevisionResult .Revision , nil
117
197
}
118
198
119
- func (c * acrService ) patchOperationWithChangeRevision (ctx context. Context , a * application. Application , revisions []string ) error {
199
+ func (c * acrService ) patchOperationWithChangeRevision (revisions []string ) map [ string ] any {
120
200
if len (revisions ) == 1 {
121
- patch , _ := json . Marshal ( map [string ]any {
201
+ return map [string ]any {
122
202
"operation" : map [string ]any {
123
203
"sync" : map [string ]any {
124
204
"changeRevision" : revisions [0 ],
125
205
},
126
206
},
127
- })
128
- _ , err := c .applicationClientset .ArgoprojV1alpha1 ().Applications (a .Namespace ).Patch (ctx , a .Name , types .MergePatchType , patch , metav1.PatchOptions {})
129
- return err
207
+ }
130
208
}
131
-
132
- patch , _ := json .Marshal (map [string ]any {
209
+ return map [string ]any {
133
210
"operation" : map [string ]any {
134
211
"sync" : map [string ]any {
135
212
"changeRevisions" : revisions ,
136
213
},
137
214
},
138
- })
139
- _ , err := c .applicationClientset .ArgoprojV1alpha1 ().Applications (a .Namespace ).Patch (ctx , a .Name , types .MergePatchType , patch , metav1.PatchOptions {})
140
- return err
215
+ }
141
216
}
142
217
143
- func (c * acrService ) patchOperationSyncResultWithChangeRevision (ctx context. Context , a * application. Application , revisions []string ) error {
218
+ func (c * acrService ) patchOperationSyncResultWithChangeRevision (revisions []string ) map [ string ] any {
144
219
if len (revisions ) == 1 {
145
- patch , _ := json . Marshal ( map [string ]any {
220
+ return map [string ]any {
146
221
"status" : map [string ]any {
147
222
"operationState" : map [string ]any {
148
223
"operation" : map [string ]any {
@@ -152,12 +227,9 @@ func (c *acrService) patchOperationSyncResultWithChangeRevision(ctx context.Cont
152
227
},
153
228
},
154
229
},
155
- })
156
- _ , err := c .applicationClientset .ArgoprojV1alpha1 ().Applications (a .Namespace ).Patch (ctx , a .Name , types .MergePatchType , patch , metav1.PatchOptions {})
157
- return err
230
+ }
158
231
}
159
-
160
- patch , _ := json .Marshal (map [string ]any {
232
+ return map [string ]any {
161
233
"status" : map [string ]any {
162
234
"operationState" : map [string ]any {
163
235
"operation" : map [string ]any {
@@ -167,9 +239,7 @@ func (c *acrService) patchOperationSyncResultWithChangeRevision(ctx context.Cont
167
239
},
168
240
},
169
241
},
170
- })
171
- _ , err := c .applicationClientset .ArgoprojV1alpha1 ().Applications (a .Namespace ).Patch (ctx , a .Name , types .MergePatchType , patch , metav1.PatchOptions {})
172
- return err
242
+ }
173
243
}
174
244
175
245
func getCurrentRevisionFromOperation (a * application.Application ) string {
0 commit comments