@@ -19,11 +19,15 @@ package framework
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "strings"
22
23
"time"
23
24
25
+ "github.com/google/go-cmp/cmp"
24
26
. "github.com/onsi/gomega"
25
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
+ "k8s.io/apimachinery/pkg/util/sets"
26
29
"sigs.k8s.io/controller-runtime/pkg/client"
30
+ "sigs.k8s.io/yaml"
27
31
28
32
clusterctlcluster "sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
29
33
)
@@ -33,13 +37,15 @@ func ValidateResourceVersionStable(ctx context.Context, proxy ClusterProxy, name
33
37
// Wait until resource versions are stable for a bit.
34
38
byf ("Check Resource versions are stable" )
35
39
var previousResourceVersions map [string ]string
40
+ var previousObjects map [string ]client.Object
36
41
Eventually (func (g Gomega ) {
37
- objectsWithResourceVersion , err := getObjectsWithResourceVersion (ctx , proxy , namespace , ownerGraphFilterFunction )
42
+ objectsWithResourceVersion , objects , err := getObjectsWithResourceVersion (ctx , proxy , namespace , ownerGraphFilterFunction )
38
43
g .Expect (err ).ToNot (HaveOccurred ())
39
44
40
45
defer func () {
41
46
// Set current resource versions as previous resource versions for the next try.
42
47
previousResourceVersions = objectsWithResourceVersion
48
+ previousObjects = objects
43
49
}()
44
50
// This is intentionally failing on the first run.
45
51
g .Expect (objectsWithResourceVersion ).To (BeComparableTo (previousResourceVersions ))
@@ -48,19 +54,73 @@ func ValidateResourceVersionStable(ctx context.Context, proxy ClusterProxy, name
48
54
// Verify resource versions are stable for a while.
49
55
byf ("Check Resource versions remain stable" )
50
56
Consistently (func (g Gomega ) {
51
- objectsWithResourceVersion , err := getObjectsWithResourceVersion (ctx , proxy , namespace , ownerGraphFilterFunction )
57
+ objectsWithResourceVersion , objects , err := getObjectsWithResourceVersion (ctx , proxy , namespace , ownerGraphFilterFunction )
52
58
g .Expect (err ).ToNot (HaveOccurred ())
53
- g .Expect (objectsWithResourceVersion ).To (BeComparableTo (previousResourceVersions ))
59
+ g .Expect (objectsWithResourceVersion ).To (BeComparableTo (previousResourceVersions ), printObjectDiff ( previousObjects , objects ) )
54
60
}, 2 * time .Minute , 15 * time .Second ).Should (Succeed (), "Resource versions didn't stay stable" )
55
61
}
56
62
57
- func getObjectsWithResourceVersion (ctx context.Context , proxy ClusterProxy , namespace string , ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction ) (map [string ]string , error ) {
63
+ func printObjectDiff (previousObjects , newObjects map [string ]client.Object ) func () string {
64
+ return func () string {
65
+ createdObjects := objectIDs (newObjects ).Difference (objectIDs (previousObjects ))
66
+ deletedObjects := objectIDs (previousObjects ).Difference (objectIDs (newObjects ))
67
+ preservedObjects := objectIDs (previousObjects ).Intersection (objectIDs (newObjects ))
68
+
69
+ var output strings.Builder
70
+
71
+ if len (createdObjects ) > 0 {
72
+ output .WriteString ("\n Detected new objects\n " )
73
+ for objID := range createdObjects {
74
+ obj := newObjects [objID ]
75
+ resourceYAML , _ := yaml .Marshal (obj )
76
+ output .WriteString (fmt .Sprintf ("\n New object %s:\n %s\n " , objID , resourceYAML ))
77
+ }
78
+ }
79
+ if len (deletedObjects ) > 0 {
80
+ output .WriteString ("\n Detected deleted objects\n " )
81
+ for objID := range deletedObjects {
82
+ obj := previousObjects [objID ]
83
+ resourceYAML , _ := yaml .Marshal (obj )
84
+ output .WriteString (fmt .Sprintf ("\n Deleted object %s:\n %s\n " , objID , resourceYAML ))
85
+ }
86
+ }
87
+
88
+ if len (preservedObjects ) > 0 {
89
+ output .WriteString ("\n Detected objects with changed resourceVersion\n " )
90
+ for objID := range preservedObjects {
91
+ previousObj := previousObjects [objID ]
92
+ newObj := newObjects [objID ]
93
+
94
+ if previousObj .GetResourceVersion () == newObj .GetResourceVersion () {
95
+ continue
96
+ }
97
+
98
+ previousResourceYAML , _ := yaml .Marshal (previousObj )
99
+ newResourceYAML , _ := yaml .Marshal (newObj )
100
+ output .WriteString (fmt .Sprintf ("\n Object with changed resourceVersion %s:\n %s\n " , objID , cmp .Diff (string (previousResourceYAML ), string (newResourceYAML ))))
101
+ }
102
+ }
103
+
104
+ return output .String ()
105
+ }
106
+ }
107
+
108
+ func objectIDs (objs map [string ]client.Object ) sets.Set [string ] {
109
+ ret := sets.Set [string ]{}
110
+ for id := range objs {
111
+ ret .Insert (id )
112
+ }
113
+ return ret
114
+ }
115
+
116
+ func getObjectsWithResourceVersion (ctx context.Context , proxy ClusterProxy , namespace string , ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction ) (map [string ]string , map [string ]client.Object , error ) {
58
117
graph , err := clusterctlcluster .GetOwnerGraph (ctx , namespace , proxy .GetKubeconfigPath (), ownerGraphFilterFunction )
59
118
if err != nil {
60
- return nil , err
119
+ return nil , nil , err
61
120
}
62
121
63
122
objectsWithResourceVersion := map [string ]string {}
123
+ objects := map [string ]client.Object {}
64
124
for _ , node := range graph {
65
125
nodeNamespacedName := client.ObjectKey {Namespace : node .Object .Namespace , Name : node .Object .Name }
66
126
obj := & metav1.PartialObjectMetadata {
@@ -70,9 +130,10 @@ func getObjectsWithResourceVersion(ctx context.Context, proxy ClusterProxy, name
70
130
},
71
131
}
72
132
if err := proxy .GetClient ().Get (ctx , nodeNamespacedName , obj ); err != nil {
73
- return nil , err
133
+ return nil , nil , err
74
134
}
75
135
objectsWithResourceVersion [fmt .Sprintf ("%s/%s/%s" , node .Object .Kind , node .Object .Namespace , node .Object .Name )] = obj .ResourceVersion
136
+ objects [fmt .Sprintf ("%s/%s/%s" , node .Object .Kind , node .Object .Namespace , node .Object .Name )] = obj
76
137
}
77
- return objectsWithResourceVersion , nil
138
+ return objectsWithResourceVersion , objects , nil
78
139
}
0 commit comments