Skip to content

Commit

Permalink
Merge pull request #11020 from k8s-infra-cherrypick-robot/cherry-pick…
Browse files Browse the repository at this point in the history
…-11012-to-release-1.8

[release-1.8] 🌱 Improve error output of ValidateResourceVersionStable
  • Loading branch information
k8s-ci-robot authored Aug 6, 2024
2 parents 4b719ae + 4393991 commit 62155e7
Showing 1 changed file with 68 additions and 7 deletions.
75 changes: 68 additions & 7 deletions test/framework/resourceversion_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ package framework
import (
"context"
"fmt"
"strings"
"time"

"github.com/google/go-cmp/cmp"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"

clusterctlcluster "sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
)
Expand All @@ -33,13 +37,15 @@ func ValidateResourceVersionStable(ctx context.Context, proxy ClusterProxy, name
// Wait until resource versions are stable for a bit.
byf("Check Resource versions are stable")
var previousResourceVersions map[string]string
var previousObjects map[string]client.Object
Eventually(func(g Gomega) {
objectsWithResourceVersion, err := getObjectsWithResourceVersion(ctx, proxy, namespace, ownerGraphFilterFunction)
objectsWithResourceVersion, objects, err := getObjectsWithResourceVersion(ctx, proxy, namespace, ownerGraphFilterFunction)
g.Expect(err).ToNot(HaveOccurred())

defer func() {
// Set current resource versions as previous resource versions for the next try.
previousResourceVersions = objectsWithResourceVersion
previousObjects = objects
}()
// This is intentionally failing on the first run.
g.Expect(objectsWithResourceVersion).To(BeComparableTo(previousResourceVersions))
Expand All @@ -48,19 +54,73 @@ func ValidateResourceVersionStable(ctx context.Context, proxy ClusterProxy, name
// Verify resource versions are stable for a while.
byf("Check Resource versions remain stable")
Consistently(func(g Gomega) {
objectsWithResourceVersion, err := getObjectsWithResourceVersion(ctx, proxy, namespace, ownerGraphFilterFunction)
objectsWithResourceVersion, objects, err := getObjectsWithResourceVersion(ctx, proxy, namespace, ownerGraphFilterFunction)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(objectsWithResourceVersion).To(BeComparableTo(previousResourceVersions))
g.Expect(objectsWithResourceVersion).To(BeComparableTo(previousResourceVersions), printObjectDiff(previousObjects, objects))
}, 2*time.Minute, 15*time.Second).Should(Succeed(), "Resource versions didn't stay stable")
}

func getObjectsWithResourceVersion(ctx context.Context, proxy ClusterProxy, namespace string, ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction) (map[string]string, error) {
func printObjectDiff(previousObjects, newObjects map[string]client.Object) func() string {
return func() string {
createdObjects := objectIDs(newObjects).Difference(objectIDs(previousObjects))
deletedObjects := objectIDs(previousObjects).Difference(objectIDs(newObjects))
preservedObjects := objectIDs(previousObjects).Intersection(objectIDs(newObjects))

var output strings.Builder

if len(createdObjects) > 0 {
output.WriteString("\nDetected new objects\n")
for objID := range createdObjects {
obj := newObjects[objID]
resourceYAML, _ := yaml.Marshal(obj)
output.WriteString(fmt.Sprintf("\nNew object %s:\n%s\n", objID, resourceYAML))
}
}
if len(deletedObjects) > 0 {
output.WriteString("\nDetected deleted objects\n")
for objID := range deletedObjects {
obj := previousObjects[objID]
resourceYAML, _ := yaml.Marshal(obj)
output.WriteString(fmt.Sprintf("\nDeleted object %s:\n%s\n", objID, resourceYAML))
}
}

if len(preservedObjects) > 0 {
output.WriteString("\nDetected objects with changed resourceVersion\n")
for objID := range preservedObjects {
previousObj := previousObjects[objID]
newObj := newObjects[objID]

if previousObj.GetResourceVersion() == newObj.GetResourceVersion() {
continue
}

previousResourceYAML, _ := yaml.Marshal(previousObj)
newResourceYAML, _ := yaml.Marshal(newObj)
output.WriteString(fmt.Sprintf("\nObject with changed resourceVersion %s:\n%s\n", objID, cmp.Diff(string(previousResourceYAML), string(newResourceYAML))))
}
}

return output.String()
}
}

func objectIDs(objs map[string]client.Object) sets.Set[string] {
ret := sets.Set[string]{}
for id := range objs {
ret.Insert(id)
}
return ret
}

func getObjectsWithResourceVersion(ctx context.Context, proxy ClusterProxy, namespace string, ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction) (map[string]string, map[string]client.Object, error) {
graph, err := clusterctlcluster.GetOwnerGraph(ctx, namespace, proxy.GetKubeconfigPath(), ownerGraphFilterFunction)
if err != nil {
return nil, err
return nil, nil, err
}

objectsWithResourceVersion := map[string]string{}
objects := map[string]client.Object{}
for _, node := range graph {
nodeNamespacedName := client.ObjectKey{Namespace: node.Object.Namespace, Name: node.Object.Name}
obj := &metav1.PartialObjectMetadata{
Expand All @@ -70,9 +130,10 @@ func getObjectsWithResourceVersion(ctx context.Context, proxy ClusterProxy, name
},
}
if err := proxy.GetClient().Get(ctx, nodeNamespacedName, obj); err != nil {
return nil, err
return nil, nil, err
}
objectsWithResourceVersion[fmt.Sprintf("%s/%s/%s", node.Object.Kind, node.Object.Namespace, node.Object.Name)] = obj.ResourceVersion
objects[fmt.Sprintf("%s/%s/%s", node.Object.Kind, node.Object.Namespace, node.Object.Name)] = obj
}
return objectsWithResourceVersion, nil
return objectsWithResourceVersion, objects, nil
}

0 comments on commit 62155e7

Please sign in to comment.