Skip to content

Commit 02a7bd9

Browse files
committed
Remove deprecated expression/ref evaluation from flux controller, fix tests
Signed-off-by: Klaudiusz Fabryczny <klaudiusz.fabryczny@sap.com>
1 parent ae06dbe commit 02a7bd9

6 files changed

Lines changed: 29 additions & 189 deletions

File tree

e2e/plugin/e2e_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ var _ = Describe("Plugin E2E", Ordered, func() {
109109
})
110110

111111
It("should resolve option values from direct plugin reference", func() {
112+
Skip("Plugin-to-Plugin ValueFrom.Ref resolution is deprecated. Use PluginPreset (#1776).")
112113
By("setting up cluster role binding for OIDC on remote cluster")
113114
expect.SetupOIDCClusterRoleBinding(ctx, remoteClient, remoteOIDCClusterRoleBindingName, remoteIntegrationCluster, env.TestNamespace)
114115

@@ -129,6 +130,7 @@ var _ = Describe("Plugin E2E", Ordered, func() {
129130
})
130131

131132
It("should resolve option values from plugin reference by label selector", func() {
133+
Skip("Plugin-to-Plugin ValueFrom.Ref resolution is deprecated. Use PluginPreset for cross-resource references (#1776).")
132134
By("executing the plugin integration scenario with plugin reference by label selector")
133135
scenarios.PluginIntegrationBySelector(ctx, adminClient, remoteClient, env, remoteIntegrationCluster)
134136
})

internal/controller/plugin/plugin_controller_flux.go

Lines changed: 7 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -460,58 +460,22 @@ func (r *PluginReconciler) fetchReleaseStatus(ctx context.Context,
460460
}
461461
}
462462

463-
// computeReleaseValues resolves Expressions and ValueFromRefs in the Plugin's option values
464-
// and inserts the Greenhouse values
465-
func computeReleaseValues(ctx context.Context, c client.Client, plugin *greenhousev1alpha1.Plugin, expressionEvaluation, integrationEnabled bool) ([]greenhousev1alpha1.PluginOptionValue, error) {
463+
// computeReleaseValues validates the Plugin's option values and inserts the Greenhouse values.
464+
// Expressions and ValueFromRefs are no longer resolved here - they must be resolved by the
465+
// PluginPreset controller before creating the Plugin.
466+
// This function only validates that all option values have either a direct value or a secret reference.
467+
func computeReleaseValues(ctx context.Context, c client.Client, plugin *greenhousev1alpha1.Plugin, _expressionEvaluation, _integrationEnabled bool) ([]greenhousev1alpha1.PluginOptionValue, error) {
466468
optionValues, err := helm.GetPluginOptionValuesForPlugin(ctx, c, plugin)
467469
if err != nil {
468470
return nil, err
469471
}
470-
trackedObjects := make([]string, 0)
471-
// initialize CEL resolver
472-
var celResolver *helm.CELResolver
473-
if expressionEvaluation {
474-
celResolver, err = helm.NewCELResolver(optionValues)
475-
if err != nil {
476-
return nil, fmt.Errorf("failed to initialize CEL resolver: %w", err)
477-
}
478-
}
479-
for i, v := range optionValues {
472+
473+
for _, v := range optionValues {
480474
switch {
481475
case v.Value != nil:
482476
// noop, direct values are already set
483477
continue
484478

485-
case v.Expression != nil:
486-
if celResolver == nil {
487-
celResolver, err = helm.NewCELResolver(optionValues)
488-
if err != nil {
489-
return nil, fmt.Errorf("failed to initialize CEL resolver: %w", err)
490-
}
491-
}
492-
// This PR adds CEL expression evaluation to the PluginPreset controller (#1774).
493-
// The Plugin controller's expression evaluation remains active (gated by feature flag)
494-
resolvedOptionValue, err := celResolver.ResolveExpression(v, expressionEvaluation)
495-
if err != nil {
496-
return nil, err
497-
}
498-
optionValues[i] = *resolvedOptionValue
499-
500-
case v.ValueFrom != nil && v.ValueFrom.Ref != nil:
501-
// TODO(#1776): References should no longer be resolved by Plugin controller.
502-
// Once PluginPreset controller handles all reference resolution,
503-
// this branch should return an error instead of resolving.
504-
if !integrationEnabled {
505-
continue
506-
}
507-
//TODO: handle external references
508-
resolvedOptionValue, objectTrackers, err := ResolveValueFromRef(ctx, c, plugin, v)
509-
if err != nil {
510-
return nil, err
511-
}
512-
trackedObjects = append(trackedObjects, objectTrackers...)
513-
optionValues[i] = *resolvedOptionValue
514-
515479
case v.ValueFrom != nil && v.ValueFrom.Secret != nil:
516480
// noop, secret refs are not resolved here
517481
continue
@@ -520,21 +484,6 @@ func computeReleaseValues(ctx context.Context, c client.Client, plugin *greenhou
520484
}
521485
}
522486

523-
// update tracking information for plugin integrations
524-
if integrationEnabled {
525-
// remove tracking annotations from resources that are no longer being tracked
526-
if err := removeUntrackedObjectAnnotations(ctx, c, plugin, trackedObjects); err != nil {
527-
// log err, will retry on next reconciliation
528-
log.FromContext(ctx).Error(err, "failed to remove untracked object annotations", "namespace", plugin.Namespace, "plugin", plugin.Name)
529-
}
530-
if len(trackedObjects) > 0 {
531-
plugin.Status.TrackedObjects = trackedObjects
532-
} else {
533-
// clear tracked objects if there are none
534-
plugin.Status.TrackedObjects = nil
535-
}
536-
}
537-
538487
return optionValues, nil
539488
}
540489

internal/controller/plugin/plugin_integration/plugin_integration_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ var _ = Describe("Plugin Integration", Ordered, func() {
9090
})
9191

9292
It("should create HelmReleases and resolve values from external references", func() {
93+
Skip("Plugin-to-Plugin ValueFrom.Ref resolution is deprecated. Use PluginPreset for cross-resource references (#1776).")
9394
By("creating alerts plugin with a label")
9495
alerts = test.NewPlugin(test.Ctx, "alerts", testNamespace,
9596
test.WithClusterPluginDefinition(testPluginDefinition.Name),
@@ -139,6 +140,7 @@ var _ = Describe("Plugin Integration", Ordered, func() {
139140
})
140141

141142
It("should track and untrack plugin dependencies", func() {
143+
Skip("Deprecated. Use PluginPreset for cross-resource references (#1776).")
142144
By("verifying tracking annotation was set on alerts")
143145
Eventually(func(g Gomega) {
144146
err := test.K8sClient.Get(test.Ctx, client.ObjectKeyFromObject(alerts), alerts)

internal/controller/plugin/plugin_values_resolver.go

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"k8s.io/apimachinery/pkg/labels"
2020
"k8s.io/apimachinery/pkg/runtime/schema"
2121
"k8s.io/apimachinery/pkg/types"
22-
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2322
"k8s.io/client-go/util/retry"
2423
"sigs.k8s.io/controller-runtime/pkg/client"
2524
"sigs.k8s.io/controller-runtime/pkg/log"
@@ -282,43 +281,6 @@ func addTrackingAnnotation(uObject *unstructured.Unstructured, tracker string) {
282281
}
283282
}
284283

285-
// removeUntrackedObjectAnnotations removes tracking annotations from resources that are no longer being tracked.
286-
// This ensures that when a Plugin A changes its value references (e.g., from Plugin B to Plugin C),
287-
// the tracking annotation is removed from the old resource (Plugin B).
288-
// It compares the current tracked objects with the previous ones and removes the tracker ID
289-
// from resources that are no longer in the tracked list.
290-
func removeUntrackedObjectAnnotations(ctx context.Context, c client.Client, plugin *greenhousev1alpha1.Plugin, currentTrackedObjects []string) error {
291-
// previously tracked objects from plugin status
292-
previousTrackedObjects := plugin.Status.TrackedObjects
293-
if len(previousTrackedObjects) == 0 {
294-
// No previous tracking, nothing to clean up
295-
return nil
296-
}
297-
298-
// find objects previously tracked objects
299-
untrackedObjects := findUntrackedObjects(previousTrackedObjects, currentTrackedObjects)
300-
if len(untrackedObjects) == 0 {
301-
// No untracked objects to clean up
302-
return nil
303-
}
304-
305-
// tracker ID for reconciling plugin
306-
tracker := trackingID(plugin.GroupVersionKind().Kind, plugin.GetName())
307-
308-
// remove tracking-id from each untracked object
309-
allErrors := make([]error, 0)
310-
for _, untrackedObjectID := range untrackedObjects {
311-
if err := removeTrackingAnnotation(ctx, c, plugin.GetNamespace(), untrackedObjectID, tracker); err != nil {
312-
log.FromContext(ctx).Error(err, "failed to remove tracking annotation from untracked object",
313-
"plugin", plugin.GetName(),
314-
"untrackedObject", untrackedObjectID)
315-
// continue on error the failed attempt can be retried on next reconciliation
316-
allErrors = append(allErrors, err)
317-
}
318-
}
319-
return utilerrors.NewAggregate(allErrors)
320-
}
321-
322284
// findUntrackedObjects returns objects that were previously tracked but are not in the current tracked list.
323285
func findUntrackedObjects(previousTracked, currentTracked []string) []string {
324286
// create a map of current tracked objects for quick lookup
@@ -338,86 +300,6 @@ func findUntrackedObjects(previousTracked, currentTracked []string) []string {
338300
return untrackedObjects
339301
}
340302

341-
// removeTrackingAnnotation removes a specific tracker ID from a resource's tracking annotation.
342-
func removeTrackingAnnotation(ctx context.Context, c client.Client, namespace, objectID, tracker string) error {
343-
kind, name, err := parseTrackingID(objectID)
344-
if err != nil {
345-
return err
346-
}
347-
gvk := buildGVK(kind)
348-
key := types.NamespacedName{
349-
Name: name,
350-
Namespace: namespace,
351-
}
352-
353-
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
354-
uObject := &unstructured.Unstructured{}
355-
uObject.SetGroupVersionKind(gvk)
356-
357-
if err := c.Get(ctx, key, uObject); err != nil {
358-
if apierrors.IsNotFound(err) {
359-
// Resource no longer exists, nothing to clean up
360-
log.FromContext(ctx).Info("untracked object not found, skipping cleanup",
361-
"kind", kind,
362-
"namespace", namespace,
363-
"name", name)
364-
return nil
365-
}
366-
return err
367-
}
368-
369-
// current annotations
370-
annotations := uObject.GetAnnotations()
371-
if annotations == nil {
372-
// No annotations, nothing to remove
373-
return nil
374-
}
375-
376-
// current tracking annotation value
377-
trackingValue, ok := annotations[greenhouseapis.AnnotationKeyPluginTackingID]
378-
if !ok || trackingValue == "" {
379-
// No tracking annotation, nothing to remove
380-
return nil
381-
}
382-
383-
// spread trackers and remove specified one
384-
trackers := strings.Split(trackingValue, trackingSeparator)
385-
updatedTrackers := make([]string, 0, len(trackers))
386-
for _, t := range trackers {
387-
if t != tracker {
388-
updatedTrackers = append(updatedTrackers, t)
389-
}
390-
}
391-
392-
switch {
393-
case len(updatedTrackers) == 0:
394-
// no trackers, remove the annotation entirely
395-
delete(annotations, greenhouseapis.AnnotationKeyPluginTackingID)
396-
log.FromContext(ctx).Info("removed tracking annotation from resource",
397-
"kind", kind,
398-
"namespace", namespace,
399-
"name", name,
400-
"tracker", tracker)
401-
402-
case len(updatedTrackers) < len(trackers):
403-
// trackers remaining, update the annotation
404-
annotations[greenhouseapis.AnnotationKeyPluginTackingID] = strings.Join(updatedTrackers, trackingSeparator)
405-
log.FromContext(ctx).Info("removed tracker from resource",
406-
"kind", kind,
407-
"namespace", namespace,
408-
"name", name,
409-
"tracker", tracker)
410-
411-
default:
412-
// no tracker found
413-
return nil
414-
}
415-
416-
uObject.SetAnnotations(annotations)
417-
return c.Update(ctx, uObject)
418-
})
419-
}
420-
421303
// buildGVK constructs a GroupVersionKind for Greenhouse resources.
422304
func buildGVK(kind string) schema.GroupVersionKind {
423305
return schema.GroupVersionKind{

internal/controller/plugin/pluginpreset_controller_test.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -901,14 +901,14 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
901901
It("should resolve a simple expression using clusterName", func() {
902902
By("creating a PluginPreset with an expression")
903903
expressionStr := `"app-${global.greenhouse.clusterName}.example.com"`
904-
pluginSpec := greenhousev1alpha1.PluginSpec{
904+
presetPluginSpec := greenhousev1alpha1.PluginPresetPluginSpec{
905905
PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{
906906
Kind: greenhousev1alpha1.ClusterPluginDefinitionKind,
907907
Name: pluginPresetDefinitionName,
908908
},
909909
ReleaseName: releaseName,
910910
ReleaseNamespace: releaseNamespace,
911-
OptionValues: []greenhousev1alpha1.PluginOptionValue{
911+
OptionValues: []greenhousev1alpha1.PluginPresetPluginOptionValue{
912912
{
913913
Name: "myRequiredOption",
914914
Value: test.MustReturnJSONFor("myValue"),
@@ -922,7 +922,7 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
922922

923923
pluginPreset := test.NewPluginPreset("expr-simple", test.TestNamespace,
924924
test.WithPluginPresetLabel(greenhouseapis.LabelKeyOwnedBy, testTeam.Name),
925-
test.WithPluginPresetPluginSpec(pluginSpec),
925+
test.WithPresetPluginSpec(presetPluginSpec),
926926
test.WithPluginPresetClusterSelector(metav1.LabelSelector{
927927
MatchLabels: map[string]string{
928928
"cluster": clusterA,
@@ -941,7 +941,6 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
941941
for _, ov := range expPlugin.Spec.OptionValues {
942942
if ov.Name == "test.hostname" {
943943
hostnameFound = true
944-
g.Expect(ov.Expression).To(BeNil(), "Expression should be resolved")
945944
g.Expect(ov.Value).ToNot(BeNil(), "Value should be set")
946945
g.Expect(string(ov.Value.Raw)).To(Equal(`"app-`+clusterA+`.example.com"`),
947946
"Expression should resolve with cluster name")
@@ -969,14 +968,14 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
969968

970969
By("creating a PluginPreset with metadata expression")
971970
expressionStr := `"service.${global.greenhouse.metadata.region}.example.com"`
972-
pluginSpec := greenhousev1alpha1.PluginSpec{
971+
presetPluginSpec := greenhousev1alpha1.PluginPresetPluginSpec{
973972
PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{
974973
Kind: greenhousev1alpha1.ClusterPluginDefinitionKind,
975974
Name: pluginPresetDefinitionName,
976975
},
977976
ReleaseName: releaseName,
978977
ReleaseNamespace: releaseNamespace,
979-
OptionValues: []greenhousev1alpha1.PluginOptionValue{
978+
OptionValues: []greenhousev1alpha1.PluginPresetPluginOptionValue{
980979
{
981980
Name: "myRequiredOption",
982981
Value: test.MustReturnJSONFor("myValue"),
@@ -990,7 +989,7 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
990989

991990
pluginPreset := test.NewPluginPreset("expr-metadata", test.TestNamespace,
992991
test.WithPluginPresetLabel(greenhouseapis.LabelKeyOwnedBy, testTeam.Name),
993-
test.WithPluginPresetPluginSpec(pluginSpec),
992+
test.WithPresetPluginSpec(presetPluginSpec),
994993
test.WithPluginPresetClusterSelector(metav1.LabelSelector{
995994
MatchLabels: map[string]string{
996995
"cluster": clusterA,
@@ -1032,14 +1031,14 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
10321031

10331032
It("should keep direct values unchanged when resolving expressions", func() {
10341033
expressionStr := `"generated-${global.greenhouse.clusterName}"`
1035-
pluginSpec := greenhousev1alpha1.PluginSpec{
1034+
presetPluginSpec := greenhousev1alpha1.PluginPresetPluginSpec{
10361035
PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{
10371036
Kind: greenhousev1alpha1.ClusterPluginDefinitionKind,
10381037
Name: pluginPresetDefinitionName,
10391038
},
10401039
ReleaseName: releaseName,
10411040
ReleaseNamespace: releaseNamespace,
1042-
OptionValues: []greenhousev1alpha1.PluginOptionValue{
1041+
OptionValues: []greenhousev1alpha1.PluginPresetPluginOptionValue{
10431042
{
10441043
Name: "myRequiredOption",
10451044
Value: test.MustReturnJSONFor("myValue"),
@@ -1057,7 +1056,7 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
10571056

10581057
pluginPreset := test.NewPluginPreset("expr-mixed", test.TestNamespace,
10591058
test.WithPluginPresetLabel(greenhouseapis.LabelKeyOwnedBy, testTeam.Name),
1060-
test.WithPluginPresetPluginSpec(pluginSpec),
1059+
test.WithPresetPluginSpec(presetPluginSpec),
10611060
test.WithPluginPresetClusterSelector(metav1.LabelSelector{
10621061
MatchLabels: map[string]string{
10631062
"cluster": clusterA,
@@ -1094,14 +1093,14 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
10941093

10951094
It("should report error for invalid expression", func() {
10961095
invalidExpressionStr := `"service.${global.greenhouse.nonexistent.field}.example.com"`
1097-
pluginSpec := greenhousev1alpha1.PluginSpec{
1096+
presetPluginSpec := greenhousev1alpha1.PluginPresetPluginSpec{
10981097
PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{
10991098
Kind: greenhousev1alpha1.ClusterPluginDefinitionKind,
11001099
Name: pluginPresetDefinitionName,
11011100
},
11021101
ReleaseName: releaseName,
11031102
ReleaseNamespace: releaseNamespace,
1104-
OptionValues: []greenhousev1alpha1.PluginOptionValue{
1103+
OptionValues: []greenhousev1alpha1.PluginPresetPluginOptionValue{
11051104
{
11061105
Name: "myRequiredOption",
11071106
Value: test.MustReturnJSONFor("myValue"),
@@ -1115,7 +1114,7 @@ var _ = Describe("PluginPreset Controller Lifecycle", Ordered, func() {
11151114

11161115
pluginPreset := test.NewPluginPreset("expr-invalid", test.TestNamespace,
11171116
test.WithPluginPresetLabel(greenhouseapis.LabelKeyOwnedBy, testTeam.Name),
1118-
test.WithPluginPresetPluginSpec(pluginSpec),
1117+
test.WithPresetPluginSpec(presetPluginSpec),
11191118
test.WithPluginPresetClusterSelector(metav1.LabelSelector{
11201119
MatchLabels: map[string]string{
11211120
"cluster": clusterA,

internal/test/resources.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,12 @@ func WithPluginPresetPluginSpec(pluginSpec greenhousev1alpha1.PluginSpec) func(*
490490
}
491491
}
492492

493+
func WithPresetPluginSpec(spec greenhousev1alpha1.PluginPresetPluginSpec) func(*greenhousev1alpha1.PluginPreset) {
494+
return func(pp *greenhousev1alpha1.PluginPreset) {
495+
pp.Spec.Plugin = spec
496+
}
497+
}
498+
493499
// WithPluginPresetLabel sets the label on a PluginPreset
494500
func WithPluginPresetLabel(key, value string) func(*greenhousev1alpha1.PluginPreset) {
495501
return func(pp *greenhousev1alpha1.PluginPreset) {

0 commit comments

Comments
 (0)