Skip to content

Commit ccfe97f

Browse files
test: manually promote paused canaries
Signed-off-by: Kostis Kapelonis <[email protected]>
1 parent 56d8aad commit ccfe97f

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

test/e2e/single_header_based_grpcroute_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,67 @@ func testSingleHeaderBasedGRPCRoute(ctx context.Context, t *testing.T, config *e
200200
return ctx
201201
}
202202
logrus.Infof("grpcRoute %q was updated", resourcesMap[GRPC_ROUTE_KEY].GetName())
203+
// Manually promote the canary by removing the pause step to allow rollout to finish
204+
unstructured.RemoveNestedField(resourcesMap[ROLLOUT_KEY].Object, "metadata", "resourceVersion")
205+
// Remove the pause step from the canary strategy steps
206+
steps, found, err := unstructured.NestedSlice(resourcesMap[ROLLOUT_KEY].Object, "spec", "strategy", "canary", "steps")
207+
if !found || err != nil {
208+
logrus.Errorf("rollout %q canary steps not found or error: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
209+
t.Error()
210+
return ctx
211+
}
212+
// Filter out the pause step from the steps array
213+
var filteredSteps []interface{}
214+
for _, step := range steps {
215+
stepMap, ok := step.(map[string]interface{})
216+
if !ok {
217+
continue
218+
}
219+
// Skip any step that contains a "pause" key
220+
if _, hasPause := stepMap["pause"]; !hasPause {
221+
filteredSteps = append(filteredSteps, step)
222+
}
223+
}
224+
err = unstructured.SetNestedSlice(resourcesMap[ROLLOUT_KEY].Object, filteredSteps, "spec", "strategy", "canary", "steps")
225+
if err != nil {
226+
logrus.Errorf("rollout %q steps update failed: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
227+
t.Error()
228+
return ctx
229+
}
230+
serializedRolloutPromotion, err := json.Marshal(resourcesMap[ROLLOUT_KEY].Object)
231+
if err != nil {
232+
logrus.Errorf("rollout %q promotion serializing was failed: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
233+
t.Error()
234+
return ctx
235+
}
236+
logrus.Infof("rollout %q promotion was serialized", resourcesMap[ROLLOUT_KEY].GetName())
237+
rolloutPromotionPatch := k8s.Patch{
238+
PatchType: types.MergePatchType,
239+
Data: serializedRolloutPromotion,
240+
}
241+
err = clusterResources.Patch(ctx, resourcesMap[ROLLOUT_KEY], rolloutPromotionPatch)
242+
if err != nil {
243+
logrus.Errorf("rollout %q promotion was failed: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
244+
t.Error()
245+
return ctx
246+
}
247+
logrus.Infof("rollout %q was promoted to finish canary deployment", resourcesMap[ROLLOUT_KEY].GetName())
248+
// Wait for rollout to reach a healthy finished state
249+
logrus.Infof("waiting for rollout %q to complete and reach healthy status", resourcesMap[ROLLOUT_KEY].GetName())
250+
err = wait.For(
251+
waitCondition.ResourceMatch(
252+
resourcesMap[ROLLOUT_KEY],
253+
getRolloutHealthyFetcher(t),
254+
),
255+
wait.WithTimeout(LONG_PERIOD),
256+
wait.WithInterval(SHORT_PERIOD),
257+
)
258+
if err != nil {
259+
logrus.Errorf("rollout %q completion was failed: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
260+
t.Error()
261+
return ctx
262+
}
263+
logrus.Infof("rollout %q completed successfully", resourcesMap[ROLLOUT_KEY].GetName())
203264
logrus.Infof("waiting for grpcRoute %q to clean up header-based routing and reset canary weight to %d", resourcesMap[GRPC_ROUTE_KEY].GetName(), FIRST_CANARY_ROUTE_WEIGHT)
204265
err = wait.For(
205266
waitCondition.ResourceMatch(
@@ -282,3 +343,24 @@ func getMatchHeaderBasedGRPCRouteFetcher(t *testing.T, targetWeight int32, targe
282343
func isHeaderBasedGRPCRouteValuesEqual(first, second gatewayv1.GRPCHeaderMatch) bool {
283344
return first.Name == second.Name && *first.Type == *second.Type && first.Value == second.Value
284345
}
346+
347+
func getRolloutHealthyFetcher(t *testing.T) func(k8s.Object) bool {
348+
return func(obj k8s.Object) bool {
349+
var rollout v1alpha1.Rollout
350+
unstructuredRollout, ok := obj.(*unstructured.Unstructured)
351+
if !ok {
352+
logrus.Error("k8s rollout object type assertion was failed")
353+
t.Error()
354+
return false
355+
}
356+
err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredRollout.Object, &rollout)
357+
if err != nil {
358+
logrus.Errorf("conversation from unstructured rollout %q to the typed rollout was failed", unstructuredRollout.GetName())
359+
t.Error()
360+
return false
361+
}
362+
// Check if rollout is healthy (completed successfully)
363+
// A rollout is considered finished when its phase is "Healthy"
364+
return rollout.Status.Phase == "Healthy"
365+
}
366+
}

test/e2e/single_header_based_httproute_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,67 @@ func testSingleHeaderBasedHTTPRoute(ctx context.Context, t *testing.T, config *e
200200
return ctx
201201
}
202202
logrus.Infof("httpRoute %q was updated", resourcesMap[HTTP_ROUTE_KEY].GetName())
203+
// Manually promote the canary by removing the pause step to allow rollout to finish
204+
unstructured.RemoveNestedField(resourcesMap[ROLLOUT_KEY].Object, "metadata", "resourceVersion")
205+
// Remove the pause step from the canary strategy steps
206+
steps, found, err := unstructured.NestedSlice(resourcesMap[ROLLOUT_KEY].Object, "spec", "strategy", "canary", "steps")
207+
if !found || err != nil {
208+
logrus.Errorf("rollout %q canary steps not found or error: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
209+
t.Error()
210+
return ctx
211+
}
212+
// Filter out the pause step from the steps array
213+
var filteredSteps []interface{}
214+
for _, step := range steps {
215+
stepMap, ok := step.(map[string]interface{})
216+
if !ok {
217+
continue
218+
}
219+
// Skip any step that contains a "pause" key
220+
if _, hasPause := stepMap["pause"]; !hasPause {
221+
filteredSteps = append(filteredSteps, step)
222+
}
223+
}
224+
err = unstructured.SetNestedSlice(resourcesMap[ROLLOUT_KEY].Object, filteredSteps, "spec", "strategy", "canary", "steps")
225+
if err != nil {
226+
logrus.Errorf("rollout %q steps update failed: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
227+
t.Error()
228+
return ctx
229+
}
230+
serializedRolloutPromotion, err := json.Marshal(resourcesMap[ROLLOUT_KEY].Object)
231+
if err != nil {
232+
logrus.Errorf("rollout %q promotion serializing was failed: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
233+
t.Error()
234+
return ctx
235+
}
236+
logrus.Infof("rollout %q promotion was serialized", resourcesMap[ROLLOUT_KEY].GetName())
237+
rolloutPromotionPatch := k8s.Patch{
238+
PatchType: types.MergePatchType,
239+
Data: serializedRolloutPromotion,
240+
}
241+
err = clusterResources.Patch(ctx, resourcesMap[ROLLOUT_KEY], rolloutPromotionPatch)
242+
if err != nil {
243+
logrus.Errorf("rollout %q promotion was failed: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
244+
t.Error()
245+
return ctx
246+
}
247+
logrus.Infof("rollout %q was promoted to finish canary deployment", resourcesMap[ROLLOUT_KEY].GetName())
248+
// Wait for rollout to reach a healthy finished state
249+
logrus.Infof("waiting for rollout %q to complete and reach healthy status", resourcesMap[ROLLOUT_KEY].GetName())
250+
err = wait.For(
251+
waitCondition.ResourceMatch(
252+
resourcesMap[ROLLOUT_KEY],
253+
getRolloutHealthyFetcher(t),
254+
),
255+
wait.WithTimeout(LONG_PERIOD),
256+
wait.WithInterval(SHORT_PERIOD),
257+
)
258+
if err != nil {
259+
logrus.Errorf("rollout %q completion was failed: %s", resourcesMap[ROLLOUT_KEY].GetName(), err)
260+
t.Error()
261+
return ctx
262+
}
263+
logrus.Infof("rollout %q completed successfully", resourcesMap[ROLLOUT_KEY].GetName())
203264
logrus.Infof("waiting for httpRoute %q to clean up header-based routing and reset canary weight to %d", resourcesMap[HTTP_ROUTE_KEY].GetName(), FIRST_CANARY_ROUTE_WEIGHT)
204265
err = wait.For(
205266
waitCondition.ResourceMatch(

0 commit comments

Comments
 (0)