5
5
"context"
6
6
"flag"
7
7
"fmt"
8
+ "io"
8
9
"log"
9
10
"os"
10
11
"path"
@@ -13,9 +14,14 @@ import (
13
14
"time"
14
15
15
16
appsv1api "k8s.io/api/apps/v1"
17
+ corev1 "k8s.io/api/core/v1"
18
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19
+ "k8s.io/apimachinery/pkg/labels"
16
20
"k8s.io/apimachinery/pkg/runtime/schema"
21
+ "k8s.io/client-go/kubernetes"
17
22
"k8s.io/client-go/kubernetes/scheme"
18
23
"sigs.k8s.io/controller-runtime/pkg/client"
24
+ "sigs.k8s.io/e2e-framework/klient/k8s"
19
25
"sigs.k8s.io/e2e-framework/klient/wait"
20
26
"sigs.k8s.io/e2e-framework/klient/wait/conditions"
21
27
"sigs.k8s.io/e2e-framework/pkg/env"
@@ -48,7 +54,7 @@ func TestMain(m *testing.M) {
48
54
kindCluster := kind .NewCluster (kindClusterName ).WithOpts (kind .WithImage (* kindImage ))
49
55
50
56
testenv .Setup (
51
- envfuncs .CreateCluster (kindCluster , kindClusterName ),
57
+ envfuncs .CreateClusterWithConfig (kindCluster , kindClusterName , "templates/kind.config" ),
52
58
envfuncs .LoadImageToCluster (kindClusterName , * agentImage ),
53
59
envfuncs .LoadImageToCluster (kindClusterName , * serverImage ),
54
60
renderAndApplyManifests ,
@@ -84,15 +90,16 @@ func renderTemplate(file string, params any) (client.Object, *schema.GroupVersio
84
90
return obj .(client.Object ), gvk , nil
85
91
}
86
92
87
- type KeyValue struct {
88
- Key string
89
- Value string
93
+ type CLIFlag struct {
94
+ Flag string
95
+ Value string
96
+ EmptyValue bool
90
97
}
91
98
92
99
type DeploymentConfig struct {
93
100
Replicas int
94
101
Image string
95
- Args []KeyValue
102
+ Args []CLIFlag
96
103
}
97
104
98
105
func renderAndApplyManifests (ctx context.Context , cfg * envconf.Config ) (context.Context , error ) {
@@ -111,10 +118,6 @@ func renderAndApplyManifests(ctx context.Context, cfg *envconf.Config) (context.
111
118
if err != nil {
112
119
return ctx , err
113
120
}
114
- agentService , _ , err := renderTemplate ("agent/service.yaml" , struct {}{})
115
- if err != nil {
116
- return ctx , err
117
- }
118
121
119
122
// Submit agent RBAC templates to k8s.
120
123
err = client .Resources ().Create (ctx , agentServiceAccount )
@@ -129,10 +132,6 @@ func renderAndApplyManifests(ctx context.Context, cfg *envconf.Config) (context.
129
132
if err != nil {
130
133
return ctx , err
131
134
}
132
- err = client .Resources ().Create (ctx , agentService )
133
- if err != nil {
134
- return ctx , err
135
- }
136
135
137
136
// Render server RBAC and Service templates.
138
137
serverClusterRoleBinding , _ , err := renderTemplate ("server/clusterrolebinding.yaml" , struct {}{})
@@ -157,50 +156,172 @@ func renderAndApplyManifests(ctx context.Context, cfg *envconf.Config) (context.
157
156
return ctx , nil
158
157
}
159
158
160
- func deployAndWaitForDeployment (obj client.Object ) func (context.Context , * testing.T , * envconf.Config ) context.Context {
159
+ func createDeployment (obj client.Object ) func (context.Context , * testing.T , * envconf.Config ) context.Context {
161
160
return func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
162
- client := cfg .Client ()
163
- err := client .Resources ().Create (ctx , obj )
161
+ deployment , ok := obj .(* appsv1api.Deployment )
162
+ if ! ok {
163
+ t .Fatalf ("object %q is not a deployment" , obj .GetName ())
164
+ }
165
+
166
+ err := cfg .Client ().Resources (deployment .Namespace ).Create (ctx , deployment )
167
+ if err != nil {
168
+ t .Fatalf ("could not create deployment %q: %v" , deployment .Name , err )
169
+ }
170
+
171
+ newDeployment := & appsv1api.Deployment {}
172
+ err = cfg .Client ().Resources (deployment .Namespace ).Get (ctx , deployment .Name , deployment .Namespace , newDeployment )
173
+ if err != nil {
174
+ t .Fatalf ("could not get deployment %q after creation: %v" , deployment .Name , err )
175
+ }
176
+
177
+ return ctx
178
+ }
179
+ }
180
+
181
+ func deleteDeployment (obj client.Object ) func (context.Context , * testing.T , * envconf.Config ) context.Context {
182
+ return func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
183
+ deployment , ok := obj .(* appsv1api.Deployment )
184
+ if ! ok {
185
+ t .Fatalf ("object %q is not a deployment" , obj .GetName ())
186
+ }
187
+
188
+ k8sClient := kubernetes .NewForConfigOrDie (cfg .Client ().RESTConfig ())
189
+ pods , err := k8sClient .CoreV1 ().Pods (deployment .Namespace ).List (ctx , metav1.ListOptions {LabelSelector : labels .FormatLabels (deployment .Spec .Selector .MatchLabels )})
164
190
if err != nil {
165
- t .Fatalf ("could not create Deployment : %v" , err )
191
+ t .Fatalf ("could not get pods for deployment %q : %v" , deployment . Name , err )
166
192
}
167
193
194
+ cfg .Client ().Resources (deployment .Namespace ).Delete (ctx , deployment )
195
+
168
196
err = wait .For (
169
- conditions .New (client .Resources ()).DeploymentAvailable (obj .GetName (), obj .GetNamespace ()),
170
- wait .WithTimeout (1 * time .Minute ),
171
- wait .WithInterval (10 * time .Second ),
197
+ conditions .New (cfg .Client ().Resources (deployment .Namespace )).ResourcesDeleted (pods ),
198
+ wait .WithTimeout (60 * time .Second ),
199
+ wait .WithInterval (5 * time .Second ),
200
+ )
201
+ if err != nil {
202
+ pods , err := k8sClient .CoreV1 ().Pods (deployment .Namespace ).List (ctx , metav1.ListOptions {LabelSelector : labels .FormatLabels (deployment .Spec .Selector .MatchLabels )})
203
+ if err != nil {
204
+ t .Fatalf ("could not get pods for deployment %q: %v" , deployment .Name , err )
205
+ }
206
+
207
+ for _ , pod := range pods .Items {
208
+ logs , err := dumpPodLogs (ctx , k8sClient , pod .Namespace , pod .Name )
209
+ if err != nil {
210
+ t .Fatalf ("could not dump logs for pod %q: %v" , pod .Name , err )
211
+ }
212
+ t .Errorf ("logs for pod %q: %v" , pod .Name , logs )
213
+ }
214
+ t .Fatalf ("waiting for deletion of pods for deployment %q failed, dumped pod logs" , deployment .Name )
215
+ }
216
+
217
+ return ctx
218
+ }
219
+ }
220
+
221
+ func sleepFor (duration time.Duration ) func (context.Context , * testing.T , * envconf.Config ) context.Context {
222
+ return func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
223
+ time .Sleep (duration )
224
+ return ctx
225
+ }
226
+ }
227
+
228
+ func waitForDeployment (obj client.Object ) func (context.Context , * testing.T , * envconf.Config ) context.Context {
229
+ return func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
230
+ deployment , ok := obj .(* appsv1api.Deployment )
231
+ if ! ok {
232
+ t .Fatalf ("object %q is not a deployment" , obj .GetName ())
233
+ }
234
+
235
+ k8sClient := kubernetes .NewForConfigOrDie (cfg .Client ().RESTConfig ())
236
+ err := wait .For (
237
+ conditions .New (cfg .Client ().Resources (deployment .Namespace )).DeploymentAvailable (deployment .Name , deployment .Namespace ),
238
+ wait .WithTimeout (60 * time .Second ),
239
+ wait .WithInterval (5 * time .Second ),
172
240
)
173
241
if err != nil {
174
- t .Fatalf ("waiting for Deployment failed: %v" , err )
242
+ pods , err := k8sClient .CoreV1 ().Pods (deployment .Namespace ).List (ctx , metav1.ListOptions {LabelSelector : labels .FormatLabels (deployment .Spec .Selector .MatchLabels )})
243
+ if err != nil {
244
+ t .Fatalf ("could not get pods for deployment %q: %v" , deployment .Name , err )
245
+ }
246
+
247
+ for _ , pod := range pods .Items {
248
+ if isPodReady (& pod ) {
249
+ continue
250
+ }
251
+
252
+ logs , err := dumpPodLogs (ctx , k8sClient , pod .Namespace , pod .Name )
253
+ if err != nil {
254
+ t .Fatalf ("could not dump logs for pod %q: %v" , pod .Name , err )
255
+ }
256
+ t .Errorf ("logs for pod %q: %v" , pod .Name , logs )
257
+ }
258
+ t .Fatalf ("waiting for deployment %q failed, dumped pod logs" , deployment .Name )
175
259
}
176
260
177
261
return ctx
178
262
}
179
263
}
180
264
265
+ func isPodReady (pod * corev1.Pod ) bool {
266
+ for _ , condition := range pod .Status .Conditions {
267
+ if condition .Type == corev1 .PodReady {
268
+ return condition .Status == corev1 .ConditionTrue
269
+ }
270
+ }
271
+ return false
272
+ }
273
+
274
+ func dumpPodLogs (ctx context.Context , k8sClient kubernetes.Interface , namespace , name string ) (string , error ) {
275
+ req := k8sClient .CoreV1 ().Pods (namespace ).GetLogs (name , & corev1.PodLogOptions {})
276
+ podLogs , err := req .Stream (ctx )
277
+ if err != nil {
278
+ return "" , fmt .Errorf ("could not stream logs for pod %q in namespace %q: %w" , name , namespace , err )
279
+ }
280
+ defer podLogs .Close ()
281
+
282
+ b , err := io .ReadAll (podLogs )
283
+ if err != nil {
284
+ return "" , fmt .Errorf ("could not read logs for pod %q in namespace %q from stream: %w" , name , namespace , err )
285
+ }
286
+
287
+ return string (b ), nil
288
+ }
289
+
181
290
func scaleDeployment (obj client.Object , replicas int ) func (context.Context , * testing.T , * envconf.Config ) context.Context {
182
291
return func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
183
292
deployment , ok := obj .(* appsv1api.Deployment )
184
293
if ! ok {
185
294
t .Fatalf ("provided object is not a deployment" )
186
295
}
187
296
297
+ err := cfg .Client ().Resources ().Get (ctx , deployment .Name , deployment .Namespace , deployment )
298
+ if err != nil {
299
+ t .Fatalf ("could not get Deployment to update (name: %q, namespace: %q): %v" , deployment .Name , deployment .Namespace , err )
300
+ }
301
+
188
302
newReplicas := int32 (replicas )
189
303
deployment .Spec .Replicas = & newReplicas
190
304
191
305
client := cfg .Client ()
192
- err : = client .Resources ().Update (ctx , deployment )
306
+ err = client .Resources ().Update (ctx , deployment )
193
307
if err != nil {
194
308
t .Fatalf ("could not update Deployment replicas: %v" , err )
195
309
}
196
310
197
311
err = wait .For (
198
- conditions .New (client .Resources ()).DeploymentAvailable (deployment .GetName (), deployment .GetNamespace ()),
199
- wait .WithTimeout (1 * time .Minute ),
200
- wait .WithInterval (10 * time .Second ),
312
+ conditions .New (cfg .Client ().Resources (deployment .Namespace )).ResourceScaled (deployment , func (obj k8s.Object ) int32 {
313
+ deployment , ok := obj .(* appsv1api.Deployment )
314
+ if ! ok {
315
+ t .Fatalf ("provided object is not a deployment" )
316
+ }
317
+
318
+ return deployment .Status .AvailableReplicas
319
+ }, int32 (replicas )),
320
+ wait .WithTimeout (60 * time .Second ),
321
+ wait .WithInterval (5 * time .Second ),
201
322
)
202
323
if err != nil {
203
- t .Fatalf ("waiting for Deployment failed: %v " , err )
324
+ t .Fatalf ("waiting for deployment %q to scale failed " , deployment . Name )
204
325
}
205
326
206
327
return ctx
0 commit comments