Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhancement: drop the redundant ApplyUnstructuredResourceImproved return value #1833

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions pkg/operator/resource/resourceapply/monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var serviceMonitorGVR = schema.GroupVersionResource{Group: "monitoring.coreos.co

// ApplyAlertmanager applies the Alertmanager.
func ApplyAlertmanager(ctx context.Context, client dynamic.Interface, recorder events.Recorder, required *unstructured.Unstructured) (*unstructured.Unstructured, bool, error) {
return ApplyUnstructuredResourceImproved(ctx, client, recorder, required, noCache, alertmanagerGVR, nil, nil)
return ApplyUnstructuredResourceImprovedDeprecated(ctx, client, recorder, required, noCache, alertmanagerGVR, nil, nil)
}

// DeleteAlertmanager deletes the Alertmanager.
Expand All @@ -32,7 +32,7 @@ func DeleteAlertmanager(ctx context.Context, client dynamic.Interface, recorder

// ApplyPrometheus applies the Prometheus.
func ApplyPrometheus(ctx context.Context, client dynamic.Interface, recorder events.Recorder, required *unstructured.Unstructured) (*unstructured.Unstructured, bool, error) {
return ApplyUnstructuredResourceImproved(ctx, client, recorder, required, noCache, prometheusGVR, nil, nil)
return ApplyUnstructuredResourceImprovedDeprecated(ctx, client, recorder, required, noCache, prometheusGVR, nil, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, what is the plan for switching to ApplyUnstructuredResourceImproved?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of doing that early in the next release to allow enough time for folks to migrate?

}

// DeletePrometheus deletes the Prometheus.
Expand All @@ -42,7 +42,7 @@ func DeletePrometheus(ctx context.Context, client dynamic.Interface, recorder ev

// ApplyPrometheusRule applies the PrometheusRule.
func ApplyPrometheusRule(ctx context.Context, client dynamic.Interface, recorder events.Recorder, required *unstructured.Unstructured) (*unstructured.Unstructured, bool, error) {
return ApplyUnstructuredResourceImproved(ctx, client, recorder, required, noCache, prometheusRuleGVR, nil, nil)
return ApplyUnstructuredResourceImprovedDeprecated(ctx, client, recorder, required, noCache, prometheusRuleGVR, nil, nil)
}

// DeletePrometheusRule deletes the PrometheusRule.
Expand All @@ -52,7 +52,7 @@ func DeletePrometheusRule(ctx context.Context, client dynamic.Interface, recorde

// ApplyServiceMonitor applies the ServiceMonitor.
func ApplyServiceMonitor(ctx context.Context, client dynamic.Interface, recorder events.Recorder, required *unstructured.Unstructured) (*unstructured.Unstructured, bool, error) {
return ApplyUnstructuredResourceImproved(ctx, client, recorder, required, noCache, serviceMonitorGVR, nil, nil)
return ApplyUnstructuredResourceImprovedDeprecated(ctx, client, recorder, required, noCache, serviceMonitorGVR, nil, nil)
}

// DeleteServiceMonitor deletes the ServiceMonitor.
Expand All @@ -72,6 +72,26 @@ func ApplyUnstructuredResourceImproved(
resourceGVR schema.GroupVersionResource,
defaultingFunc mimicDefaultingFunc,
equalityChecker equalityChecker,
) (*unstructured.Unstructured, error) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jan--f I believe this satisfies the proposed refactor we talked about earlier?

gotUnstructured, _, err := ApplyUnstructuredResourceImprovedDeprecated(ctx, client, recorder, required, cache, resourceGVR, defaultingFunc, equalityChecker)
return gotUnstructured, err
}

// Deprecated: Use ApplyUnstructuredResourceImproved instead.
// NOTE: The return values (excluding the *unstructured.Unstructured one) establish the following matrix (w.r.t. the create or update verbs):
// * true, nil : verb action needed; operation successful
// * false, nil : verb action not needed; operation skipped
// * true, error : verb action needed, operation unsuccessful
// * false, error: verb action may or may not be needed; operation unsuccessful
func ApplyUnstructuredResourceImprovedDeprecated(
ctx context.Context,
client dynamic.Interface,
recorder events.Recorder,
required *unstructured.Unstructured,
cache ResourceCache,
resourceGVR schema.GroupVersionResource,
defaultingFunc mimicDefaultingFunc,
equalityChecker equalityChecker,
) (*unstructured.Unstructured, bool, error) {
name := required.GetName()
namespace := required.GetNamespace()
Expand Down
92 changes: 71 additions & 21 deletions test/e2e-monitoring/monitoring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package e2e_monitoring

import (
"context"
"os"
"testing"

"github.com/openshift/library-go/pkg/operator/events"
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
"github.com/openshift/library-go/test/library"
monv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/api/errors"
Expand All @@ -16,10 +16,45 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
)

const (
noUpdate = iota
metadataUpdate
specAndMaybeMetadataUpdate
)

// didUpdate compares two unstructured resources and returns if the specified parts changed.
func didUpdate(old, new *unstructured.Unstructured) (int, error) {
oldResourceVersion, _, err := unstructured.NestedString(old.Object, "metadata", "resourceVersion")
if err != nil {
return 0, err
}
newResourceVersion, _, err := unstructured.NestedString(new.Object, "metadata", "resourceVersion")
if err != nil {
return 0, err
}
oldGeneration, _, err := unstructured.NestedInt64(old.Object, "metadata", "generation")
if err != nil {
return 0, err
}
newGeneration, _, err := unstructured.NestedInt64(new.Object, "metadata", "generation")
if err != nil {
return 0, err
}
if oldResourceVersion != newResourceVersion {
if oldGeneration != newGeneration {
return specAndMaybeMetadataUpdate, nil
}
return metadataUpdate, nil
}

return noUpdate, nil
}

func TestResourceVersionApplication(t *testing.T) {
config, err := library.NewClientConfigForTest()
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
require.NoError(t, err)

// Define the resource.
Expand Down Expand Up @@ -68,7 +103,8 @@ func TestResourceVersionApplication(t *testing.T) {
unstructuredResourceMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&resource)
require.NoError(t, err)
unstructuredResource.SetUnstructuredContent(unstructuredResourceMap)
gotUnstructured, didUpdate, err := resourceapply.ApplyUnstructuredResourceImproved(
oldUnstructuredResource := unstructuredResource.DeepCopy()
gotUnstructuredResource, err := resourceapply.ApplyUnstructuredResourceImproved(
context.TODO(),
dynamicClient,
recorder,
Expand All @@ -81,15 +117,19 @@ func TestResourceVersionApplication(t *testing.T) {
if err != nil && !errors.IsAlreadyExists(err) {
t.Fatalf("Failed to create resource: %v", err)
}
require.True(t, didUpdate)
expectation, err := didUpdate(oldUnstructuredResource, gotUnstructuredResource)
if err != nil {
t.Fatalf("Failed to compare resources: %v", err)
}
require.True(t, expectation != noUpdate)

// Update the resource version and the generation since we made a spec change.
unstructuredResource.SetResourceVersion(gotUnstructured.GetResourceVersion())
unstructuredResource.SetGeneration(gotUnstructured.GetGeneration())
unstructuredResource.SetCreationTimestamp(gotUnstructured.GetCreationTimestamp())
unstructuredResource.SetUID(gotUnstructured.GetUID())
unstructuredResource.SetManagedFields(gotUnstructured.GetManagedFields())
require.Equal(t, unstructuredResource.UnstructuredContent(), gotUnstructured.UnstructuredContent())
unstructuredResource.SetResourceVersion(gotUnstructuredResource.GetResourceVersion())
unstructuredResource.SetGeneration(gotUnstructuredResource.GetGeneration())
unstructuredResource.SetCreationTimestamp(gotUnstructuredResource.GetCreationTimestamp())
unstructuredResource.SetUID(gotUnstructuredResource.GetUID())
unstructuredResource.SetManagedFields(gotUnstructuredResource.GetManagedFields())
require.Equal(t, unstructuredResource.UnstructuredContent(), gotUnstructuredResource.UnstructuredContent())
Comment on lines +127 to +132
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are already doing this now, LMK if the didUpdate function above feels redundant now. I kept it to visualize the workaround for the didUpdate return parameter in the test.


// Compare the existing resource with the one we have.
existingResourceUnstructured, err := dynamicClient.Resource(gvr).Namespace(resource.GetNamespace()).Get(context.TODO(), resource.GetName(), metav1.GetOptions{})
Expand All @@ -101,7 +141,8 @@ func TestResourceVersionApplication(t *testing.T) {
unstructuredResourceMap, err = runtime.DefaultUnstructuredConverter.ToUnstructured(&resource)
require.NoError(t, err)
unstructuredResource.SetUnstructuredContent(unstructuredResourceMap)
gotUnstructured, didUpdate, err = resourceapply.ApplyUnstructuredResourceImproved(
oldUnstructuredResource = gotUnstructuredResource.DeepCopy()
gotUnstructuredResource, err = resourceapply.ApplyUnstructuredResourceImproved(
context.TODO(),
dynamicClient,
recorder,
Expand All @@ -114,23 +155,28 @@ func TestResourceVersionApplication(t *testing.T) {
if err != nil {
t.Fatalf("Failed to update resource: %v", err)
}
require.True(t, didUpdate)
expectation, err = didUpdate(oldUnstructuredResource, gotUnstructuredResource)
if err != nil {
t.Fatalf("Failed to compare resources: %v", err)
}
require.True(t, expectation == specAndMaybeMetadataUpdate)

// Update the resource version and the generation since we made a spec change.
unstructuredResource.SetResourceVersion(gotUnstructured.GetResourceVersion())
unstructuredResource.SetGeneration(gotUnstructured.GetGeneration())
unstructuredResource.SetCreationTimestamp(gotUnstructured.GetCreationTimestamp())
unstructuredResource.SetUID(gotUnstructured.GetUID())
unstructuredResource.SetManagedFields(gotUnstructured.GetManagedFields())
require.Equal(t, unstructuredResource.UnstructuredContent(), gotUnstructured.UnstructuredContent())
unstructuredResource.SetResourceVersion(gotUnstructuredResource.GetResourceVersion())
unstructuredResource.SetGeneration(gotUnstructuredResource.GetGeneration())
unstructuredResource.SetCreationTimestamp(gotUnstructuredResource.GetCreationTimestamp())
unstructuredResource.SetUID(gotUnstructuredResource.GetUID())
unstructuredResource.SetManagedFields(gotUnstructuredResource.GetManagedFields())
require.Equal(t, unstructuredResource.UnstructuredContent(), gotUnstructuredResource.UnstructuredContent())

// Compare the existing resource with the one we have.
existingResourceUnstructured, err = dynamicClient.Resource(gvr).Namespace(resource.GetNamespace()).Get(context.TODO(), resource.GetName(), metav1.GetOptions{})
require.NoError(t, err)
require.Equal(t, unstructuredResource.UnstructuredContent(), existingResourceUnstructured.UnstructuredContent())

// Update the resource without any changes, without specifying a resource version.
gotUnstructured, didUpdate, err = resourceapply.ApplyUnstructuredResourceImproved(
oldUnstructuredResource = gotUnstructuredResource.DeepCopy()
gotUnstructuredResource, err = resourceapply.ApplyUnstructuredResourceImproved(
context.TODO(),
dynamicClient,
recorder,
Expand All @@ -143,10 +189,14 @@ func TestResourceVersionApplication(t *testing.T) {
if err != nil {
t.Fatalf("Failed to update resource: %v", err)
}
require.False(t, didUpdate)
expectation, err = didUpdate(oldUnstructuredResource, gotUnstructuredResource)
if err != nil {
t.Fatalf("Failed to compare resources: %v", err)
}
require.True(t, expectation == noUpdate)

// Do not update any fields as no change was made.
require.Equal(t, unstructuredResource.UnstructuredContent(), gotUnstructured.UnstructuredContent())
require.Equal(t, unstructuredResource.UnstructuredContent(), gotUnstructuredResource.UnstructuredContent())

// Compare the existing resource with the one we have.
existingResourceUnstructured, err = dynamicClient.Resource(gvr).Namespace(resource.GetNamespace()).Get(context.TODO(), resource.GetName(), metav1.GetOptions{})
Expand Down