Skip to content

Commit c92d26d

Browse files
ishtmeet.singhishtoo1
authored andcommitted
feat: wire managers and add cascade delete skeleton
Summary: Intent: - Wire TriggerRunManager and PipelineRunManager into the pipeline controller - Add handleDeletion method with no-children path (removes finalizer immediately) Changes: - Add triggerRunManager and pipelineRunManager fields to Reconciler struct - Construct managers in Register after handler creation - Replace deletion stub with handleDeletion that lists children and removes finalizer if none - Register field indexes on fake client for tests - Add TestCascadeDelete_NoChildren test Test Plan: - go test ./components/pipeline/... -v -count=1 (all tests pass) Revert Plan: Revert this PR via git revert. Jira Issues:
1 parent b8b524e commit c92d26d

3 files changed

Lines changed: 277 additions & 22 deletions

File tree

go/components/pipeline/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ go_library(
1313
"//go/api:go_default_library",
1414
"//go/api/handler:go_default_library",
1515
"//go/base/env:go_default_library",
16+
"//go/components/pipelinerun:go_default_library",
17+
"//go/components/triggerrun:go_default_library",
1618
"//proto/api:go_default_library",
1719
"//proto/api/v2:go_default_library",
1820
"@com_github_prometheus_client_golang//prometheus:go_default_library",
@@ -35,6 +37,8 @@ go_test(
3537
"//go/api:go_default_library",
3638
"//go/api/handler:go_default_library",
3739
"//go/base/env:go_default_library",
40+
"//go/components/pipelinerun:go_default_library",
41+
"//go/components/triggerrun:go_default_library",
3842
"//proto/api:go_default_library",
3943
"//proto/api/v2:go_default_library",
4044
"@com_github_stretchr_testify//require:go_default_library",
@@ -44,6 +48,7 @@ go_test(
4448
"@io_k8s_sigs_controller_runtime//:go_default_library",
4549
"@io_k8s_sigs_controller_runtime//pkg/client:go_default_library",
4650
"@io_k8s_sigs_controller_runtime//pkg/client/fake:go_default_library",
51+
"@io_k8s_sigs_controller_runtime//pkg/client/interceptor:go_default_library",
4752
"@io_k8s_sigs_controller_runtime//pkg/controller/controllerutil:go_default_library",
4853
"@org_uber_go_zap//zaptest:go_default_library",
4954
],

go/components/pipeline/controller.go

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"github.com/michelangelo-ai/michelangelo/go/api"
2222
apiHandler "github.com/michelangelo-ai/michelangelo/go/api/handler"
2323
"github.com/michelangelo-ai/michelangelo/go/base/env"
24+
"github.com/michelangelo-ai/michelangelo/go/components/pipelinerun"
25+
"github.com/michelangelo-ai/michelangelo/go/components/triggerrun"
2426
apipb "github.com/michelangelo-ai/michelangelo/proto-go/api"
2527
v2pb "github.com/michelangelo-ai/michelangelo/proto-go/api/v2"
2628
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -41,9 +43,11 @@ const (
4143
// operations and maintains environment context and logging capabilities.
4244
type Reconciler struct {
4345
api.Handler
44-
env env.Context
45-
logger *zap.Logger
46-
apiHandlerFactory apiHandler.Factory
46+
env env.Context
47+
logger *zap.Logger
48+
apiHandlerFactory apiHandler.Factory
49+
triggerRunManager triggerrun.Manager
50+
pipelineRunManager pipelinerun.Manager
4751
}
4852

4953
// Reconcile is the main reconciliation loop entry point for Pipeline resources.
@@ -75,14 +79,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
7579
}
7680
}
7781
} else {
78-
// Pipeline is being deleted — remove finalizer to allow deletion
79-
// Cascade delete logic will be added in a subsequent PR
80-
logger.Info("Pipeline is being deleted, removing finalizer")
81-
controllerutil.RemoveFinalizer(pipeline, api.PipelineFinalizer)
82-
if err := r.Update(ctx, pipeline, &metav1.UpdateOptions{}); err != nil {
83-
return ctrl.Result{}, fmt.Errorf("remove pipeline finalizer: %w", err)
84-
}
85-
return ctrl.Result{}, nil
82+
return r.handleDeletion(ctx, pipeline, logger)
8683
}
8784

8885
originalPipeline := pipeline.DeepCopy()
@@ -139,6 +136,55 @@ func (r *Reconciler) updatePipelineStatus(ctx context.Context, pipeline *v2pb.Pi
139136
return result, nil
140137
}
141138

139+
func (r *Reconciler) handleDeletion(ctx context.Context, pipeline *v2pb.Pipeline, logger *zap.Logger) (ctrl.Result, error) {
140+
// If the finalizer is not present we don't own this deletion; nothing to cascade.
141+
// Avoids wasted list/kill/delete work on pipelines that pre-date the finalizer rollout.
142+
if !controllerutil.ContainsFinalizer(pipeline, api.PipelineFinalizer) {
143+
return ctrl.Result{}, nil
144+
}
145+
logger.Info("Pipeline is being deleted, starting cascade delete")
146+
147+
triggerRuns, err := r.triggerRunManager.ListTriggerRunsForPipeline(ctx, pipeline.Namespace, pipeline.Name)
148+
if err != nil {
149+
logger.Error("Failed to list trigger runs for cascade delete",
150+
zap.Error(err),
151+
zap.String("operation", "list_trigger_runs"),
152+
zap.String("namespace", pipeline.Namespace),
153+
zap.String("name", pipeline.Name))
154+
return ctrl.Result{}, fmt.Errorf("list trigger runs for pipeline %s/%s: %w", pipeline.Namespace, pipeline.Name, err)
155+
}
156+
157+
pipelineRuns, err := r.pipelineRunManager.ListPipelineRunsForPipeline(ctx, pipeline.Namespace, pipeline.Name)
158+
if err != nil {
159+
logger.Error("Failed to list pipeline runs for cascade delete",
160+
zap.Error(err),
161+
zap.String("operation", "list_pipeline_runs"),
162+
zap.String("namespace", pipeline.Namespace),
163+
zap.String("name", pipeline.Name))
164+
return ctrl.Result{}, fmt.Errorf("list pipeline runs for pipeline %s/%s: %w", pipeline.Namespace, pipeline.Name, err)
165+
}
166+
167+
if len(triggerRuns) == 0 && len(pipelineRuns) == 0 {
168+
logger.Info("No children found, removing finalizer")
169+
controllerutil.RemoveFinalizer(pipeline, api.PipelineFinalizer)
170+
if updateErr := r.Update(ctx, pipeline, &metav1.UpdateOptions{}); updateErr != nil {
171+
logger.Error("Failed to remove finalizer after cascade delete",
172+
zap.Error(updateErr),
173+
zap.String("operation", "remove_finalizer"),
174+
zap.String("namespace", pipeline.Namespace),
175+
zap.String("name", pipeline.Name))
176+
return ctrl.Result{}, fmt.Errorf("remove finalizer on pipeline %s/%s: %w", pipeline.Namespace, pipeline.Name, updateErr)
177+
}
178+
return ctrl.Result{}, nil
179+
}
180+
181+
// Kill and delete steps will be added in subsequent PRs
182+
logger.Info("Children found, requeueing for cascade delete",
183+
zap.Int("triggerRuns", len(triggerRuns)),
184+
zap.Int("pipelineRuns", len(pipelineRuns)))
185+
return ctrl.Result{RequeueAfter: reconcileInterval}, nil
186+
}
187+
142188
// formatRevisionName generates a standardized revision name for a pipeline.
143189
//
144190
// The name format is: "pipeline-{lowercase-pipeline-name}-{git-ref-prefix}"
@@ -176,6 +222,8 @@ func (r *Reconciler) Register(mgr ctrl.Manager) error {
176222
return err
177223
}
178224
r.Handler = handler
225+
r.triggerRunManager = triggerrun.NewManager(mgr.GetClient(), r.logger)
226+
r.pipelineRunManager = pipelinerun.NewManager(mgr.GetClient(), r.logger)
179227
return ctrl.NewControllerManagedBy(mgr).
180228
For(&v2pb.Pipeline{}).
181229
Complete(r)

0 commit comments

Comments
 (0)