Skip to content

Commit 509b01a

Browse files
authored
feat(basic-pull): add custom destination annotations for Application (#161)
Introduce two optional annotations to override the default destination behavior in the basic pull model: - apps.open-cluster-management.io/destination-name - apps.open-cluster-management.io/destination-server When either annotation is present, the controller uses the provided value instead of the hardcoded default. This allows users to specify custom destination configurations like in-cluster for destination name or alternative server URLs. Signed-off-by: Mike Ng <ming@redhat.com>
1 parent 0c71369 commit 509b01a

File tree

4 files changed

+403
-7
lines changed

4 files changed

+403
-7
lines changed

internal/basic/application/application_controller.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ const (
3939
AnnotationKeyOCMManagedCluster = "apps.open-cluster-management.io/ocm-managed-cluster"
4040
// Application annotation that dictates which managed cluster namespace this Application should be pulled to
4141
AnnotationKeyOCMManagedClusterAppNamespace = "apps.open-cluster-management.io/ocm-managed-cluster-app-namespace"
42+
// Application annotation that allows specifying a custom destination name (ie, in-cluster)
43+
AnnotationKeyDestinationName = "apps.open-cluster-management.io/destination-name"
44+
// Application annotation that allows specifying a custom destination server URL (ie, https://kubernetes.default.svc)
45+
AnnotationKeyDestinationServer = "apps.open-cluster-management.io/destination-server"
4246
// Application and ManifestWork annotation that shows which ApplicationSet is the grand parent of this work
4347
AnnotationKeyAppSet = "apps.open-cluster-management.io/hosting-applicationset"
4448
// Application annotation that enables the skip reconcilation of an application

internal/basic/application/helper.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func getAppSetOwnerName(ownerRefs []metav1.OwnerReference) string {
109109
// prepareApplicationForWorkPayload modifies the Application:
110110
// - reset the meta
111111
// - set the namespace value
112-
// - ensures the Application Destination is set to in-cluster resource deployment
112+
// - ensures the Application Destination is set based on annotations or defaults to server KubernetesInternalAPIServerAddr
113113
// - ensures the operation field is also set if present
114114
func prepareApplicationForWorkPayload(application *unstructured.Unstructured) unstructured.Unstructured {
115115
newApp := &unstructured.Unstructured{}
@@ -130,10 +130,27 @@ func prepareApplicationForWorkPayload(application *unstructured.Unstructured) un
130130
// set the spec field
131131
if newSpec, ok := application.Object["spec"].(map[string]interface{}); ok {
132132
if destination, ok := newSpec["destination"].(map[string]interface{}); ok {
133-
// empty the name
134-
destination["name"] = ""
135-
// always set for in-cluster destination
136-
destination["server"] = KubernetesInternalAPIServerAddr
133+
annos := application.GetAnnotations()
134+
customName, hasCustomName := annos[AnnotationKeyDestinationName]
135+
customServer, hasCustomServer := annos[AnnotationKeyDestinationServer]
136+
137+
if hasCustomName || hasCustomServer {
138+
// custom annotations present - only set the fields that have annotations
139+
if hasCustomName {
140+
destination["name"] = customName
141+
} else {
142+
destination["name"] = ""
143+
}
144+
if hasCustomServer {
145+
destination["server"] = customServer
146+
} else {
147+
destination["server"] = ""
148+
}
149+
} else {
150+
// default behavior
151+
destination["name"] = ""
152+
destination["server"] = KubernetesInternalAPIServerAddr
153+
}
137154
}
138155
newApp.Object["spec"] = newSpec
139156
}
@@ -152,7 +169,9 @@ func prepareApplicationForWorkPayload(application *unstructured.Unstructured) un
152169
for key, value := range application.GetAnnotations() {
153170
if key != AnnotationKeyOCMManagedCluster &&
154171
key != AnnotationKeyOCMManagedClusterAppNamespace &&
155-
key != AnnotationKeyAppSkipReconcile {
172+
key != AnnotationKeyAppSkipReconcile &&
173+
key != AnnotationKeyDestinationName &&
174+
key != AnnotationKeyDestinationServer {
156175
annotations[key] = value
157176
}
158177
}

internal/basic/application/helper_test.go

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,46 @@ func Test_prepareApplicationForWorkPayload(t *testing.T) {
330330
},
331331
}
332332

333+
// Create an application with custom destination-name annotation
334+
appWithDestName := &unstructured.Unstructured{}
335+
appWithDestName.SetGroupVersionKind(schema.GroupVersionKind{
336+
Group: "argoproj.io",
337+
Version: "v1alpha1",
338+
Kind: "Application",
339+
})
340+
appWithDestName.SetName("app2")
341+
appWithDestName.SetNamespace("argocd")
342+
appWithDestName.SetFinalizers([]string{"app2-final"})
343+
appWithDestName.SetAnnotations(map[string]string{
344+
AnnotationKeyDestinationName: "in-cluster",
345+
})
346+
appWithDestName.Object["spec"] = map[string]interface{}{
347+
"destination": map[string]interface{}{
348+
"name": "originalName",
349+
"server": "originalServer",
350+
},
351+
}
352+
353+
// Create an application with custom destination-server annotation
354+
appWithDestServer := &unstructured.Unstructured{}
355+
appWithDestServer.SetGroupVersionKind(schema.GroupVersionKind{
356+
Group: "argoproj.io",
357+
Version: "v1alpha1",
358+
Kind: "Application",
359+
})
360+
appWithDestServer.SetName("app3")
361+
appWithDestServer.SetNamespace("argocd")
362+
appWithDestServer.SetFinalizers([]string{"app3-final"})
363+
appWithDestServer.SetAnnotations(map[string]string{
364+
AnnotationKeyDestinationServer: "https://custom-server:6443",
365+
})
366+
appWithDestServer.Object["spec"] = map[string]interface{}{
367+
"destination": map[string]interface{}{
368+
"name": "originalName",
369+
"server": "originalServer",
370+
},
371+
}
372+
333373
type args struct {
334374
application *unstructured.Unstructured
335375
}
@@ -339,7 +379,7 @@ func Test_prepareApplicationForWorkPayload(t *testing.T) {
339379
want *unstructured.Unstructured
340380
}{
341381
{
342-
name: "modified app",
382+
name: "default behavior - no custom destination annotations",
343383
args: args{application: app},
344384
want: func() *unstructured.Unstructured {
345385
expectedApp := &unstructured.Unstructured{}
@@ -384,6 +424,54 @@ func Test_prepareApplicationForWorkPayload(t *testing.T) {
384424
return expectedApp
385425
}(),
386426
},
427+
{
428+
name: "custom destination-name annotation",
429+
args: args{application: appWithDestName},
430+
want: func() *unstructured.Unstructured {
431+
expectedApp := &unstructured.Unstructured{}
432+
expectedApp.SetGroupVersionKind(schema.GroupVersionKind{
433+
Group: "argoproj.io",
434+
Version: "v1alpha1",
435+
Kind: "Application",
436+
})
437+
expectedApp.SetName("app2")
438+
expectedApp.SetNamespace("argocd")
439+
expectedApp.SetFinalizers([]string{"app2-final"})
440+
expectedApp.SetLabels(map[string]string{})
441+
expectedApp.SetAnnotations(map[string]string{})
442+
expectedApp.Object["spec"] = map[string]interface{}{
443+
"destination": map[string]interface{}{
444+
"name": "in-cluster",
445+
"server": "",
446+
},
447+
}
448+
return expectedApp
449+
}(),
450+
},
451+
{
452+
name: "custom destination-server annotation",
453+
args: args{application: appWithDestServer},
454+
want: func() *unstructured.Unstructured {
455+
expectedApp := &unstructured.Unstructured{}
456+
expectedApp.SetGroupVersionKind(schema.GroupVersionKind{
457+
Group: "argoproj.io",
458+
Version: "v1alpha1",
459+
Kind: "Application",
460+
})
461+
expectedApp.SetName("app3")
462+
expectedApp.SetNamespace("argocd")
463+
expectedApp.SetFinalizers([]string{"app3-final"})
464+
expectedApp.SetLabels(map[string]string{})
465+
expectedApp.SetAnnotations(map[string]string{})
466+
expectedApp.Object["spec"] = map[string]interface{}{
467+
"destination": map[string]interface{}{
468+
"name": "",
469+
"server": "https://custom-server:6443",
470+
},
471+
}
472+
return expectedApp
473+
}(),
474+
},
387475
}
388476
for _, tt := range tests {
389477
t.Run(tt.name, func(t *testing.T) {

0 commit comments

Comments
 (0)