diff --git a/operator/api/v1alpha1/common/phases.go b/operator/api/v1alpha1/common/phases.go index e479ec921d..f3f43bde5a 100644 --- a/operator/api/v1alpha1/common/phases.go +++ b/operator/api/v1alpha1/common/phases.go @@ -18,4 +18,5 @@ var ( PhaseAppPreEvaluation = KeptnPhaseType{LongName: "App Pre-Deployment Evaluations", ShortName: "AppPreDeployEvaluations"} PhaseAppPostEvaluation = KeptnPhaseType{LongName: "App Post-Deployment Evaluations", ShortName: "AppPostDeployEvaluations"} PhaseAppDeployment = KeptnPhaseType{LongName: "App Deployment", ShortName: "AppDeploy"} + PhaseCompleted = KeptnPhaseType{LongName: "Completed", ShortName: "Completed"} ) diff --git a/operator/api/v1alpha1/keptnappversion_types.go b/operator/api/v1alpha1/keptnappversion_types.go index af52a01fed..4eadb8a19e 100644 --- a/operator/api/v1alpha1/keptnappversion_types.go +++ b/operator/api/v1alpha1/keptnappversion_types.go @@ -44,9 +44,9 @@ type KeptnAppVersionStatus struct { // +kubebuilder:default:=Pending PostDeploymentEvaluationStatus common.KeptnState `json:"postDeploymentEvaluationStatus,omitempty"` // +kubebuilder:default:=Pending - WorkloadOverallStatus common.KeptnState `json:"workloadOverallStatus,omitempty"` - WorkloadStatus []WorkloadStatus `json:"workloadStatus,omitempty"` - + WorkloadOverallStatus common.KeptnState `json:"workloadOverallStatus,omitempty"` + WorkloadStatus []WorkloadStatus `json:"workloadStatus,omitempty"` + CurrentPhase string `json:"currentPhase,omitempty"` PreDeploymentTaskStatus []TaskStatus `json:"preDeploymentTaskStatus,omitempty"` PostDeploymentTaskStatus []TaskStatus `json:"postDeploymentTaskStatus,omitempty"` PreDeploymentEvaluationTaskStatus []EvaluationStatus `json:"preDeploymentEvaluationTaskStatus,omitempty"` diff --git a/operator/api/v1alpha1/keptnworkloadinstance_types.go b/operator/api/v1alpha1/keptnworkloadinstance_types.go index 3c5af77fb8..7cf1297a7f 100644 --- a/operator/api/v1alpha1/keptnworkloadinstance_types.go +++ b/operator/api/v1alpha1/keptnworkloadinstance_types.go @@ -51,6 +51,7 @@ type KeptnWorkloadInstanceStatus struct { PostDeploymentEvaluationTaskStatus []EvaluationStatus `json:"postDeploymentEvaluationTaskStatus,omitempty"` StartTime metav1.Time `json:"startTime,omitempty"` EndTime metav1.Time `json:"endTime,omitempty"` + CurrentPhase string `json:"currentPhase,omitempty"` } type TaskStatus struct { diff --git a/operator/controllers/keptnappversion/controller.go b/operator/controllers/keptnappversion/controller.go index 20f54523ec..998d1ba9fb 100644 --- a/operator/controllers/keptnappversion/controller.go +++ b/operator/controllers/keptnappversion/controller.go @@ -99,7 +99,7 @@ func (r *KeptnAppVersionReconciler) Reconcile(ctx context.Context, req ctrl.Requ reconcilePreDep := func() (common.KeptnState, error) { return r.reconcilePrePostDeployment(ctx, appVersion, common.PreDeploymentCheckType) } - return r.handlePhase(appVersion, phase, span, appVersion.IsPreDeploymentFailed, reconcilePreDep) + return r.handlePhase(ctx, appVersion, phase, span, appVersion.IsPreDeploymentFailed, reconcilePreDep) } phase = common.PhaseAppPreEvaluation @@ -107,7 +107,7 @@ func (r *KeptnAppVersionReconciler) Reconcile(ctx context.Context, req ctrl.Requ reconcilePreEval := func() (common.KeptnState, error) { return r.reconcilePrePostEvaluation(ctx, appVersion, common.PreDeploymentEvaluationCheckType) } - return r.handlePhase(appVersion, phase, span, appVersion.IsPreDeploymentEvaluationFailed, reconcilePreEval) + return r.handlePhase(ctx, appVersion, phase, span, appVersion.IsPreDeploymentEvaluationFailed, reconcilePreEval) } phase = common.PhaseAppDeployment @@ -115,7 +115,7 @@ func (r *KeptnAppVersionReconciler) Reconcile(ctx context.Context, req ctrl.Requ reconcileAppDep := func() (common.KeptnState, error) { return r.reconcileWorkloads(ctx, appVersion) } - return r.handlePhase(appVersion, phase, span, appVersion.AreWorkloadsFailed, reconcileAppDep) + return r.handlePhase(ctx, appVersion, phase, span, appVersion.AreWorkloadsFailed, reconcileAppDep) } @@ -124,7 +124,7 @@ func (r *KeptnAppVersionReconciler) Reconcile(ctx context.Context, req ctrl.Requ reconcilePostDep := func() (common.KeptnState, error) { return r.reconcilePrePostDeployment(ctx, appVersion, common.PostDeploymentCheckType) } - return r.handlePhase(appVersion, phase, span, appVersion.IsPostDeploymentFailed, reconcilePostDep) + return r.handlePhase(ctx, appVersion, phase, span, appVersion.IsPostDeploymentFailed, reconcilePostDep) } phase = common.PhaseAppPostEvaluation @@ -132,7 +132,7 @@ func (r *KeptnAppVersionReconciler) Reconcile(ctx context.Context, req ctrl.Requ reconcilePostEval := func() (common.KeptnState, error) { return r.reconcilePrePostEvaluation(ctx, appVersion, common.PostDeploymentEvaluationCheckType) } - return r.handlePhase(appVersion, phase, span, appVersion.IsPostDeploymentEvaluationFailed, reconcilePostEval) + return r.handlePhase(ctx, appVersion, phase, span, appVersion.IsPostDeploymentEvaluationFailed, reconcilePostEval) } r.recordEvent(phase, "Normal", appVersion, "Finished", "is finished") @@ -147,6 +147,7 @@ func (r *KeptnAppVersionReconciler) Reconcile(ctx context.Context, req ctrl.Requ if !appVersion.IsEndTimeSet() { // metrics: decrement active app counter r.Meters.AppActive.Add(ctx, -1, appVersion.GetActiveMetricsAttributes()...) + appVersion.Status.CurrentPhase = common.PhaseCompleted.ShortName appVersion.SetEndTime() } @@ -180,9 +181,10 @@ func (r *KeptnAppVersionReconciler) recordEvent(phase common.KeptnPhaseType, eve r.Recorder.Event(appVersion, eventType, fmt.Sprintf("%s%s", phase.ShortName, shortReason), fmt.Sprintf("%s %s / Namespace: %s, Name: %s, Version: %s ", phase.LongName, longReason, appVersion.Namespace, appVersion.Name, appVersion.Spec.Version)) } -func (r *KeptnAppVersionReconciler) handlePhase(appVersion *klcv1alpha1.KeptnAppVersion, phase common.KeptnPhaseType, span trace.Span, phaseFailed func() bool, reconcilePhase func() (common.KeptnState, error)) (ctrl.Result, error) { - +func (r *KeptnAppVersionReconciler) handlePhase(ctx context.Context, appVersion *klcv1alpha1.KeptnAppVersion, phase common.KeptnPhaseType, span trace.Span, phaseFailed func() bool, reconcilePhase func() (common.KeptnState, error)) (ctrl.Result, error) { r.Log.Info(phase.LongName + " not finished") + oldPhase := appVersion.Status.CurrentPhase + appVersion.Status.CurrentPhase = phase.ShortName if phaseFailed() { //TODO eventually we should decide whether a task returns FAILED, currently we never have this status set r.recordEvent(phase, "Warning", appVersion, "Failed", "has failed") return ctrl.Result{Requeue: true, RequeueAfter: 60 * time.Second}, nil @@ -198,5 +200,10 @@ func (r *KeptnAppVersionReconciler) handlePhase(appVersion *klcv1alpha1.KeptnApp } else { r.recordEvent(phase, "Warning", appVersion, "NotFinished", "has not finished") } + if oldPhase != appVersion.Status.CurrentPhase { + if err := r.Status().Update(ctx, appVersion); err != nil { + r.Log.Error(err, "could not update status") + } + } return ctrl.Result{Requeue: true, RequeueAfter: 5 * time.Second}, nil } diff --git a/operator/controllers/keptnworkloadinstance/controller.go b/operator/controllers/keptnworkloadinstance/controller.go index 980cb02df9..5ac02cc5b6 100644 --- a/operator/controllers/keptnworkloadinstance/controller.go +++ b/operator/controllers/keptnworkloadinstance/controller.go @@ -132,7 +132,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcilePre := func() (common.KeptnState, error) { return r.reconcilePrePostDeployment(ctx, workloadInstance, common.PreDeploymentCheckType) } - return r.handlePhase(workloadInstance, phase, span, workloadInstance.IsPreDeploymentFailed, reconcilePre) + return r.handlePhase(ctx, workloadInstance, phase, span, workloadInstance.IsPreDeploymentFailed, reconcilePre) } //Wait for pre-evaluation checks of Workload @@ -141,7 +141,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcilePreEval := func() (common.KeptnState, error) { return r.reconcilePrePostEvaluation(ctx, workloadInstance, common.PreDeploymentEvaluationCheckType) } - return r.handlePhase(workloadInstance, phase, span, workloadInstance.IsPreDeploymentEvaluationFailed, reconcilePreEval) + return r.handlePhase(ctx, workloadInstance, phase, span, workloadInstance.IsPreDeploymentEvaluationFailed, reconcilePreEval) } //Wait for deployment of Workload @@ -150,7 +150,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcileWorkloadInstance := func() (common.KeptnState, error) { return r.reconcileDeployment(ctx, workloadInstance) } - return r.handlePhase(workloadInstance, phase, span, workloadInstance.IsDeploymentFailed, reconcileWorkloadInstance) + return r.handlePhase(ctx, workloadInstance, phase, span, workloadInstance.IsDeploymentFailed, reconcileWorkloadInstance) } //Wait for post-deployment checks of Workload @@ -159,7 +159,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcilePostDeployment := func() (common.KeptnState, error) { return r.reconcilePrePostDeployment(ctx, workloadInstance, common.PostDeploymentCheckType) } - return r.handlePhase(workloadInstance, phase, span, workloadInstance.IsPostDeploymentFailed, reconcilePostDeployment) + return r.handlePhase(ctx, workloadInstance, phase, span, workloadInstance.IsPostDeploymentFailed, reconcilePostDeployment) } //Wait for post-evaluation checks of Workload @@ -168,13 +168,14 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcilePostEval := func() (common.KeptnState, error) { return r.reconcilePrePostEvaluation(ctx, workloadInstance, common.PostDeploymentEvaluationCheckType) } - return r.handlePhase(workloadInstance, phase, span, workloadInstance.IsPostDeploymentEvaluationFailed, reconcilePostEval) + return r.handlePhase(ctx, workloadInstance, phase, span, workloadInstance.IsPostDeploymentEvaluationFailed, reconcilePostEval) } // WorkloadInstance is completed at this place if !workloadInstance.IsEndTimeSet() { // metrics: decrement active deployment counter r.Meters.DeploymentActive.Add(ctx, -1, workloadInstance.GetActiveMetricsAttributes()...) + workloadInstance.Status.CurrentPhase = common.PhaseCompleted.ShortName workloadInstance.SetEndTime() } @@ -199,9 +200,10 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr return ctrl.Result{}, nil } -func (r *KeptnWorkloadInstanceReconciler) handlePhase(workloadInstance *klcv1alpha1.KeptnWorkloadInstance, phase common.KeptnPhaseType, span trace.Span, phaseFailed func() bool, reconcilePhase func() (common.KeptnState, error)) (ctrl.Result, error) { - +func (r *KeptnWorkloadInstanceReconciler) handlePhase(ctx context.Context, workloadInstance *klcv1alpha1.KeptnWorkloadInstance, phase common.KeptnPhaseType, span trace.Span, phaseFailed func() bool, reconcilePhase func() (common.KeptnState, error)) (ctrl.Result, error) { r.Log.Info(phase.LongName + " not finished") + oldPhase := workloadInstance.Status.CurrentPhase + workloadInstance.Status.CurrentPhase = phase.ShortName if phaseFailed() { //TODO eventually we should decide whether a task returns FAILED, currently we never have this status set r.recordEvent(phase, "Warning", workloadInstance, "Failed", "has failed") return ctrl.Result{Requeue: true, RequeueAfter: 60 * time.Second}, nil @@ -217,6 +219,11 @@ func (r *KeptnWorkloadInstanceReconciler) handlePhase(workloadInstance *klcv1alp } else { r.recordEvent(phase, "Warning", workloadInstance, "NotFinished", "has not finished") } + if oldPhase != workloadInstance.Status.CurrentPhase { + if err := r.Status().Update(ctx, workloadInstance); err != nil { + r.Log.Error(err, "could not update status") + } + } return ctrl.Result{Requeue: true, RequeueAfter: 5 * time.Second}, nil }