Skip to content

Commit 51be43f

Browse files
authored
feat: backport monorepocontroller annotations to acr controller (#433)
* feat: backport monorepocontroller annotations to acr controller Signed-off-by: Eugene Doudine <[email protected]> * test: improved acr_service tests Improved to check annotations, annotations feature flag and handle more error/no-op conditions Signed-off-by: Eugene Doudine <[email protected]> --------- Signed-off-by: Eugene Doudine <[email protected]>
1 parent 400bfbe commit 51be43f

File tree

5 files changed

+195
-67
lines changed

5 files changed

+195
-67
lines changed

acr_controller/controller/controller.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ type ACRController interface {
2424
type applicationChangeRevisionController struct {
2525
appBroadcaster Broadcaster
2626
acrService service.ACRService
27+
useAnnotations bool
2728
}
2829

29-
func NewApplicationChangeRevisionController(appInformer cache.SharedIndexInformer, applicationServiceClient appclient.ApplicationClient, applicationClientset appclientset.Interface) ACRController {
30+
func NewApplicationChangeRevisionController(appInformer cache.SharedIndexInformer, applicationServiceClient appclient.ApplicationClient, applicationClientset appclientset.Interface, useAnnotations bool) ACRController {
3031
appBroadcaster := NewBroadcaster()
3132
_, err := appInformer.AddEventHandler(appBroadcaster)
3233
if err != nil {
@@ -35,6 +36,7 @@ func NewApplicationChangeRevisionController(appInformer cache.SharedIndexInforme
3536
return &applicationChangeRevisionController{
3637
appBroadcaster: appBroadcaster,
3738
acrService: service.NewACRService(applicationClientset, applicationServiceClient),
39+
useAnnotations: useAnnotations,
3840
}
3941
}
4042

@@ -46,7 +48,7 @@ func (c *applicationChangeRevisionController) Run(ctx context.Context) {
4648
return nil // ignore this event
4749
}
4850

49-
return c.acrService.ChangeRevision(ctx, &a)
51+
return c.acrService.ChangeRevision(ctx, &a, c.useAnnotations)
5052
}
5153

5254
// TODO: move to abstraction

acr_controller/server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type ACRServerOpts struct {
5454
ApplicationNamespaces []string
5555
BaseHRef string
5656
RootPath string
57+
DisableAnnotations bool
5758
}
5859

5960
type handlerSwitcher struct {
@@ -96,7 +97,7 @@ func (a *ACRServer) Init(ctx context.Context) {
9697
}
9798

9899
func (a *ACRServer) RunController(ctx context.Context) {
99-
controller := acr_controller.NewApplicationChangeRevisionController(a.appInformer, a.ApplicationServiceClient, a.applicationClientset)
100+
controller := acr_controller.NewApplicationChangeRevisionController(a.appInformer, a.ApplicationServiceClient, a.applicationClientset, !a.DisableAnnotations)
100101
go controller.Run(ctx)
101102
}
102103

acr_controller/service/acr_service.go

Lines changed: 104 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package service
33
import (
44
"context"
55
"encoding/json"
6+
"fmt"
67
"sync"
78

89
log "github.com/sirupsen/logrus"
@@ -16,8 +17,15 @@ import (
1617
appclientset "github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned"
1718
)
1819

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+
1927
type ACRService interface {
20-
ChangeRevision(ctx context.Context, application *application.Application) error
28+
ChangeRevision(ctx context.Context, application *application.Application, useAnnotations bool) error
2129
}
2230

2331
type acrService struct {
@@ -55,7 +63,7 @@ func getChangeRevision(app *application.Application) string {
5563
return ""
5664
}
5765

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 {
5967
c.lock.Lock()
6068
defer c.lock.Unlock()
6169

@@ -73,36 +81,108 @@ func (c *acrService) ChangeRevision(ctx context.Context, a *application.Applicat
7381
return nil
7482
}
7583

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)
7790
if err != nil {
7891
return err
7992
}
8093

94+
var revisions []string
8195
if revision == nil || *revision == "" {
8296
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}
84100
}
85101

86-
c.logger.Infof("Change revision for application %s is %s", app.Name, *revision)
87-
88102
app, err = c.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(ctx, app.Name, metav1.GetOptions{})
89103
if err != nil {
90104
return err
91105
}
92106

93-
revisions := []string{*revision}
107+
patchMap := make(map[string]any, 2)
94108

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+
}
98117
}
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+
}
99136

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+
}
102142
}
103143

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) {
106186
c.logger.Infof("Calculate revision for application '%s', current revision '%s', previous revision '%s'", a.Name, currentRevision, previousRevision)
107187
changeRevisionResult, err := c.applicationServiceClient.GetChangeRevision(ctx, &appclient.ChangeRevisionRequest{
108188
AppName: ptr.To(a.GetName()),
@@ -116,33 +196,28 @@ func (c *acrService) calculateRevision(ctx context.Context, a *application.Appli
116196
return changeRevisionResult.Revision, nil
117197
}
118198

119-
func (c *acrService) patchOperationWithChangeRevision(ctx context.Context, a *application.Application, revisions []string) error {
199+
func (c *acrService) patchOperationWithChangeRevision(revisions []string) map[string]any {
120200
if len(revisions) == 1 {
121-
patch, _ := json.Marshal(map[string]any{
201+
return map[string]any{
122202
"operation": map[string]any{
123203
"sync": map[string]any{
124204
"changeRevision": revisions[0],
125205
},
126206
},
127-
})
128-
_, err := c.applicationClientset.ArgoprojV1alpha1().Applications(a.Namespace).Patch(ctx, a.Name, types.MergePatchType, patch, metav1.PatchOptions{})
129-
return err
207+
}
130208
}
131-
132-
patch, _ := json.Marshal(map[string]any{
209+
return map[string]any{
133210
"operation": map[string]any{
134211
"sync": map[string]any{
135212
"changeRevisions": revisions,
136213
},
137214
},
138-
})
139-
_, err := c.applicationClientset.ArgoprojV1alpha1().Applications(a.Namespace).Patch(ctx, a.Name, types.MergePatchType, patch, metav1.PatchOptions{})
140-
return err
215+
}
141216
}
142217

143-
func (c *acrService) patchOperationSyncResultWithChangeRevision(ctx context.Context, a *application.Application, revisions []string) error {
218+
func (c *acrService) patchOperationSyncResultWithChangeRevision(revisions []string) map[string]any {
144219
if len(revisions) == 1 {
145-
patch, _ := json.Marshal(map[string]any{
220+
return map[string]any{
146221
"status": map[string]any{
147222
"operationState": map[string]any{
148223
"operation": map[string]any{
@@ -152,12 +227,9 @@ func (c *acrService) patchOperationSyncResultWithChangeRevision(ctx context.Cont
152227
},
153228
},
154229
},
155-
})
156-
_, err := c.applicationClientset.ArgoprojV1alpha1().Applications(a.Namespace).Patch(ctx, a.Name, types.MergePatchType, patch, metav1.PatchOptions{})
157-
return err
230+
}
158231
}
159-
160-
patch, _ := json.Marshal(map[string]any{
232+
return map[string]any{
161233
"status": map[string]any{
162234
"operationState": map[string]any{
163235
"operation": map[string]any{
@@ -167,9 +239,7 @@ func (c *acrService) patchOperationSyncResultWithChangeRevision(ctx context.Cont
167239
},
168240
},
169241
},
170-
})
171-
_, err := c.applicationClientset.ArgoprojV1alpha1().Applications(a.Namespace).Patch(ctx, a.Name, types.MergePatchType, patch, metav1.PatchOptions{})
172-
return err
242+
}
173243
}
174244

175245
func getCurrentRevisionFromOperation(a *application.Application) string {

0 commit comments

Comments
 (0)