diff --git a/docs/pipelineruns.md b/docs/pipelineruns.md index e93d17bdbb1..9af26993753 100644 --- a/docs/pipelineruns.md +++ b/docs/pipelineruns.md @@ -18,6 +18,7 @@ weight: 4 - [Specifying `Workspaces`](#specifying-workspaces) - [Specifying `LimitRange` values](#specifying-limitrange-values) - [Configuring a failure timeout](#configuring-a-failure-timeout) +- [Monitoring execution status](#monitoring-execution-status) - [Cancelling a `PipelineRun`](#cancelling-a-pipelinerun) - [Events](events.md#pipelineruns) @@ -337,6 +338,70 @@ The `timeout` value is a `duration` conforming to Go's values are `1h30m`, `1h`, `1m`, and `60s`. If you set the global timeout to 0, all `PipelineRuns` that do not have an idividual timeout set will fail immediately upon encountering an error. +## Monitoring execution status + +As your `PipelineRun` executes, its `status` field accumulates information on the execution of each `TaskRun` +as well as the `PipelineRun` as a whole. This information includes the name of the pipeline `Task` associated +to a `TaskRun`, the complete [status of the `TaskrRun`](taskruns.md#monitoring-execution-status) and details +about `Conditions` that may be associated to a `TaskRun`. + +The following example shows an extract from tje `status` field of a `PipelineRun` that has executed successfully: + +```yaml +completionTime: "2020-05-04T02:19:14Z" +conditions: +- lastTransitionTime: "2020-05-04T02:19:14Z" + message: 'Tasks Completed: 4, Skipped: 0' + reason: Succeeded + status: "True" + type: Succeeded +startTime: "2020-05-04T02:00:11Z" +taskRuns: + triggers-release-nightly-frwmw-build-ng2qk: + pipelineTaskName: build + status: + completionTime: "2020-05-04T02:10:49Z" + conditions: + - lastTransitionTime: "2020-05-04T02:10:49Z" + message: All Steps have completed executing + reason: Succeeded + status: "True" + type: Succeeded + podName: triggers-release-nightly-frwmw-build-ng2qk-pod-8vj99 + resourcesResult: + - key: commit + resourceRef: + name: git-source-triggers-frwmw + value: 9ab5a1234166a89db352afa28f499d596ebb48db + startTime: "2020-05-04T02:05:07Z" + steps: + - container: step-build + imageID: docker-pullable://golang@sha256:a90f2671330831830e229c3554ce118009681ef88af659cd98bfafd13d5594f9 + name: build + terminated: + containerID: docker://6b6471f501f59dbb7849f5cdde200f4eeb64302b862a27af68821a7fb2c25860 + exitCode: 0 + finishedAt: "2020-05-04T02:10:45Z" + reason: Completed + startedAt: "2020-05-04T02:06:24Z" + ``` + +The following tables shows how to read the overall status of a `PipelineRun`: + +`status`|`reason`|`completionTime` is set|PipelineRun status +:-------|:-------|:---------------------:|--------------: +Unknown|Started|No|The `PipelineRun` has just been picked up by the controller. +Unknown|Running|No|The `PipelineRun` has been validate and started to perform its work. +Unknown|PipelineRunCancelled|No|The user requested the PipelineRun to be cancelled. Cancellation has not be done yet. +True|Succeeded|Yes|The `PipelineRun` completed successfully. +False|Failed|Yes|The `PipelineRun` failed because one of the `TaskRuns` failed. +False|\[Error message\]|Yes|The `PipelineRun` failed with a permanent error (usually validation). +False|PipelineRunCancelled|Yes|The `PipelineRun` was cancelled successfully. +False|PipelineRunTimeout|Yes|The `PipelineRun` timed out. +False|\[Error message\]|No|The `PipelineRun` encountered an error, but it's still running. + +When a `PipelineRun` changes status, [events](events.md#pipelineruns) are triggered accordingly. + ## Cancelling a `PipelineRun` To cancel a `PipelineRun` that's currently executing, update its definition diff --git a/docs/taskruns.md b/docs/taskruns.md index bdf083987e4..638b30617f6 100644 --- a/docs/taskruns.md +++ b/docs/taskruns.md @@ -155,7 +155,7 @@ point for the `Pod` in which the container images specified in your `Task` will customize the `Pod` configuration specifically for that `TaskRun`. In the following example, the `Task` specifies a `volumeMount` (`my-cache`) object, also provided by the `TaskRun`, -using a `PersistentVolumeClaim` volume. A specific scheduler is also configured in the `SchedulerName` field. +using a `PersistentVolumeClaim` volume. A specific scheduler is also configured in the `SchedulerName` field. The `Pod` executes with regular (non-root) user permissions. ```yaml @@ -281,7 +281,7 @@ For more information, see [`ServiceAccount`](auth.md). ## Monitoring execution status As your `TaskRun` executes, its `status` field accumulates information on the execution of each `Step` -as well as the `TaskRun` as a whole. This information includes start and stop times, exit codes, the +as well as the `TaskRun` as a whole. This information includes start and stop times, exit codes, the fully-qualified name of the container image, and the corresponding digest. **Note:** If any `Pods` have been [`OOMKilled`](https://kubernetes.io/docs/tasks/administer-cluster/out-of-resource/) @@ -311,6 +311,22 @@ steps: startedAt: "2019-08-12T18:22:54Z" ``` +The following tables shows how to read the overall status of a `TaskRun`: + +`status`|`reason`|`completionTime` is set|TaskRun status +:-------|:-------|:---------------------:|--------------: +Unknown|Started|No|The TaskRun has just been picked up by the controller. +Unknown|Running|No|The TaskRun has been validate and started to perform its work. +Unknown|TaskRunCancelled|No|The user requested the TaskRun to be cancelled. Cancellation has not be done yet. +True|Succeeded|Yes|The TaskRun completed successfully. +False|Failed|Yes|The TaskRun failed because one of the steps failed. +False|\[Error message\]|Yes|The TaskRun failed with a permanent error (usually validation). +False|TaskRunCancelled|Yes|The TaskRun was cancelled successfully. +False|TaskRunTimeout|Yes|The TaskRun timed out. +False|\[Error message\]|No|The TaskRun encountered an error, but it's still running. + +When a `TaskRun` changes status, [events](events.md#taskruns) are triggered accordingly. + ### Monitoring `Steps` If multiple `Steps` are defined in the `Task` invoked by the `TaskRun`, you can monitor their execution diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_types.go b/pkg/apis/pipeline/v1beta1/pipelinerun_types.go index 6e9823ee67b..9a6cae2e1aa 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_types.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_types.go @@ -220,6 +220,32 @@ type PipelineRunStatus struct { PipelineRunStatusFields `json:",inline"` } +// PipelineRunSucceededReason represents a reason for the pipeline run "Succeeded" condition +type PipelineRunSucceededReason string + +const ( + // PipelineRunSucceededReasonStarted is the reason set when the PipelineRun has just started + PipelineRunSucceededReasonStarted PipelineRunSucceededReason = "Started" + // PipelineRunSucceededReasonRunning is the reason set when the PipelineRun is running + PipelineRunSucceededReasonRunning PipelineRunSucceededReason = "Running" + // PipelineRunSucceededReasonSuccessful is the reason set when the PipelineRun completed successfully + PipelineRunSucceededReasonSuccessful PipelineRunSucceededReason = "Succeeded" + // PipelineRunSucceededReasonCompleted is the reason set when the PipelineRun completed successfully with one or more skipped Tasks + PipelineRunSucceededReasonCompleted PipelineRunSucceededReason = "Completed" + // PipelineRunSucceededReasonFailed is the reason set when the PipelineRun completed with a failure + PipelineRunSucceededReasonFailed PipelineRunSucceededReason = "Failed" + // PipelineRunSucceededReasonCancelled is the reason set when the PipelineRun cancelled by the user + // This reason may be found with a corev1.ConditionFalse status, if the cancellation was processed successfully + // This reason may be found with a corev1.ConditionUnknown status, if the cancellation is being processed or failed + PipelineRunSucceededReasonCancelled PipelineRunSucceededReason = "Cancelled" + // PipelineRunSucceededReasonTimedOut is the reason set when the PipelineRun has timed out + PipelineRunSucceededReasonTimedOut PipelineRunSucceededReason = "PipelineRunTimeout" +) + +func (t PipelineRunSucceededReason) String() string { + return string(t) +} + var pipelineRunCondSet = apis.NewBatchConditionSet() // GetCondition returns the Condition matching the given type. @@ -236,7 +262,12 @@ func (pr *PipelineRunStatus) InitializeConditions() { if pr.StartTime.IsZero() { pr.StartTime = &metav1.Time{Time: time.Now()} } - pipelineRunCondSet.Manage(pr).InitializeConditions() + conditionManager := pipelineRunCondSet.Manage(pr) + conditionManager.InitializeConditions() + // Ensure the started reason is set for the "Succeeded" condition + initialCondition := conditionManager.GetCondition(apis.ConditionSucceeded) + initialCondition.Reason = TaskRunSucceededReasonStarted.String() + conditionManager.SetCondition(*initialCondition) } // SetCondition sets the condition, unsetting previous conditions with the same diff --git a/pkg/apis/pipeline/v1beta1/run_interface.go b/pkg/apis/pipeline/v1beta1/run_interface.go index ddaf2ffb979..303ab4af4b7 100644 --- a/pkg/apis/pipeline/v1beta1/run_interface.go +++ b/pkg/apis/pipeline/v1beta1/run_interface.go @@ -23,20 +23,48 @@ import ( // RunsToCompletionStatus is implemented by TaskRun.Status and PipelineRun.Status type RunsToCompletionStatus interface { + + // GetCondition returns the Condition for the specified ConditionType GetCondition(t apis.ConditionType) *apis.Condition + + // InitializeConditions is used to set up the initial conditions for the + // RunsToCompletion when it's initially started InitializeConditions() + + // SetCondition is used to set up a conditions for the specified ConditionType SetCondition(newCond *apis.Condition) } // RunsToCompletion is implemented by TaskRun and PipelineRun type RunsToCompletion interface { + + // GetTypeMeta returns the TypeMeta GetTypeMeta() *metav1.TypeMeta + + // GetObjectMeta returns the ObjectMeta GetObjectMeta() *metav1.ObjectMeta + + // GetOwnerReference returns the RunsToCompletion as owner reference for any related object GetOwnerReference() metav1.OwnerReference + + // GetStatus returns the status as RunsToCompletionStatus GetStatus() RunsToCompletionStatus + + // IsDone returns true once the reconcile work on the resource is complete + // except for postrun actions (stop timeout timer, emit events, record metrics) IsDone() bool + + // HasStarted returns true after the RunsToCompletion has been reconciled for + // the first time. It must be true after InitializeConditions has been invoked + // on the associated RunsToCompletionStatus HasStarted() bool + + // IsCancelled returns true if the user marked the RunsToCompletion for cancellation IsCancelled() bool + + // HasTimedOut returns true once the RunsToCompletion has passed its maximum run time HasTimedOut() bool + + // GetRunKey returns the RunsToCompletion keuy which is equeued in the controller queue GetRunKey() string } diff --git a/pkg/apis/pipeline/v1beta1/taskrun_types.go b/pkg/apis/pipeline/v1beta1/taskrun_types.go index 3e52a29054d..ff981b7e6ee 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_types.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_types.go @@ -72,10 +72,6 @@ const ( // TaskRunSpecStatusCancelled indicates that the user wants to cancel the task, // if not already cancelled or terminated TaskRunSpecStatusCancelled = "TaskRunCancelled" - - // TaskRunReasonCancelled indicates that the TaskRun has been cancelled - // because it was requested so by the user - TaskRunReasonCancelled = "TaskRunCancelled" ) // TaskRunInputs holds the input values that this task was invoked with. @@ -102,6 +98,43 @@ type TaskRunStatus struct { TaskRunStatusFields `json:",inline"` } +// TaskRunSucceededReason is an enum used to store all TaskRun reason for +// the Succeeded condition that are controlled by the TaskRun itself. Failure +// reasons that emerge from underlying resources are not included here +type TaskRunSucceededReason string + +const ( + // TaskRunSucceededReasonStarted is the reason set when the TaskRun has just started + TaskRunSucceededReasonStarted TaskRunSucceededReason = "Started" + // TaskRunSucceededReasonRunning is the reason set when the TaskRun is running + TaskRunSucceededReasonRunning TaskRunSucceededReason = "Running" + // TaskRunSucceededReasonSuccessful is the reason set when the TaskRun completed successfully + TaskRunSucceededReasonSuccessful TaskRunSucceededReason = "Succeeded" + // TaskRunSucceededReasonFailed is the reason set when the TaskRun completed with a failure + TaskRunSucceededReasonFailed TaskRunSucceededReason = "Failed" + // TaskRunSucceededReasonCancelled is the reason set when the Taskrun is cancelled by the user + TaskRunSucceededReasonCancelled TaskRunSucceededReason = "TaskRunCancelled" + // TaskRunSucceededReasonTimedOut is the reason set when the Taskrun has timed out + TaskRunSucceededReasonTimedOut TaskRunSucceededReason = "TaskRunTimeout" +) + +func (t TaskRunSucceededReason) String() string { + return string(t) +} + +// GetStartedReason returns the reason set to the "Succeeded" condition when +// InitializeConditions is invoked +func (trs *TaskRunStatus) GetStartedReason() string { + return TaskRunSucceededReasonStarted.String() +} + +// GetRunningReason returns the reason set to the "Succeeded" condition when +// the RunsToCompletion starts running. This is used indicate that the resource +// could be validated is starting to perform its job. +func (trs *TaskRunStatus) GetRunningReason() string { + return TaskRunSucceededReasonRunning.String() +} + // MarkResourceNotConvertible adds a Warning-severity condition to the resource noting // that it cannot be converted to a higher version. func (trs *TaskRunStatus) MarkResourceNotConvertible(err *CannotConvertError) { @@ -116,11 +149,11 @@ func (trs *TaskRunStatus) MarkResourceNotConvertible(err *CannotConvertError) { // MarkResourceFailed sets the ConditionSucceeded condition to ConditionFalse // based on an error that occurred and a reason -func (trs *TaskRunStatus) MarkResourceFailed(reason string, err error) { +func (trs *TaskRunStatus) MarkResourceFailed(reason TaskRunSucceededReason, err error) { taskRunCondSet.Manage(trs).SetCondition(apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: reason, + Reason: reason.String(), Message: err.Error(), }) } @@ -211,7 +244,12 @@ func (trs *TaskRunStatus) InitializeConditions() { if trs.StartTime.IsZero() { trs.StartTime = &metav1.Time{Time: time.Now()} } - taskRunCondSet.Manage(trs).InitializeConditions() + conditionManager := taskRunCondSet.Manage(trs) + conditionManager.InitializeConditions() + // Ensure the started reason is set for the "Succeeded" condition + initialCondition := conditionManager.GetCondition(apis.ConditionSucceeded) + initialCondition.Reason = TaskRunSucceededReasonStarted.String() + conditionManager.SetCondition(*initialCondition) } // SetCondition sets the condition, unsetting previous conditions with the same diff --git a/pkg/pod/status.go b/pkg/pod/status.go index 8a372129cf7..c81cfe2fee1 100644 --- a/pkg/pod/status.go +++ b/pkg/pod/status.go @@ -45,13 +45,6 @@ const ( // that taskrun failed runtime validation ReasonFailedValidation = "TaskRunValidationFailed" - // ReasonRunning indicates that the reason for the inprogress status is that the TaskRun - // is just starting to be reconciled - ReasonRunning = "Running" - - // ReasonTimedOut indicates that the TaskRun has taken longer than its configured timeout - ReasonTimedOut = "TaskRunTimeout" - // ReasonExceededResourceQuota indicates that the TaskRun failed to create a pod due to // a ResourceQuota in the namespace ReasonExceededResourceQuota = "ExceededResourceQuota" @@ -68,13 +61,6 @@ const ( // is that the creation of the pod backing the TaskRun failed ReasonPodCreationFailed = "PodCreationFailed" - // ReasonSucceeded indicates that the reason for the finished status is that all of the steps - // completed successfully - ReasonSucceeded = "Succeeded" - - // ReasonFailed indicates that the reason for the failure status is unknown or that one of the steps failed - ReasonFailed = "Failed" - //timeFormat is RFC3339 with millisecond timeFormat = "2006-01-02T15:04:05.000Z07:00" ) @@ -114,7 +100,7 @@ func MakeTaskRunStatus(logger *zap.SugaredLogger, tr v1beta1.TaskRun, pod *corev trs.SetCondition(&apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionUnknown, - Reason: ReasonRunning, + Reason: v1beta1.TaskRunSucceededReasonRunning.String(), Message: "Not all Steps in the Task have finished executing", }) } @@ -197,14 +183,14 @@ func updateCompletedTaskRun(trs *v1beta1.TaskRunStatus, pod *corev1.Pod) { trs.SetCondition(&apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonFailed, + Reason: v1beta1.TaskRunSucceededReasonFailed.String(), Message: msg, }) } else { trs.SetCondition(&apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionTrue, - Reason: ReasonSucceeded, + Reason: v1beta1.TaskRunSucceededReasonSuccessful.String(), Message: "All Steps have completed executing", }) } @@ -219,7 +205,7 @@ func updateIncompleteTaskRun(trs *v1beta1.TaskRunStatus, pod *corev1.Pod) { trs.SetCondition(&apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionUnknown, - Reason: ReasonRunning, + Reason: v1beta1.TaskRunSucceededReasonRunning.String(), Message: "Not all Steps in the Task have finished executing", }) case corev1.PodPending: diff --git a/pkg/pod/status_test.go b/pkg/pod/status_test.go index 5d6f2cc9cca..5c058fed148 100644 --- a/pkg/pod/status_test.go +++ b/pkg/pod/status_test.go @@ -36,7 +36,7 @@ func TestMakeTaskRunStatus(t *testing.T) { conditionRunning := apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionUnknown, - Reason: ReasonRunning, + Reason: v1beta1.TaskRunSucceededReasonRunning.String(), Message: "Not all Steps in the Task have finished executing", } for _, c := range []struct { @@ -146,7 +146,7 @@ func TestMakeTaskRunStatus(t *testing.T) { Conditions: []apis.Condition{{ Type: apis.ConditionSucceeded, Status: corev1.ConditionTrue, - Reason: ReasonSucceeded, + Reason: v1beta1.TaskRunSucceededReasonSuccessful.String(), Message: "All Steps have completed executing", }}, }, @@ -214,7 +214,7 @@ func TestMakeTaskRunStatus(t *testing.T) { Conditions: []apis.Condition{{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonFailed, + Reason: v1beta1.TaskRunSucceededReasonFailed.String(), Message: "\"step-failure\" exited with code 123 (image: \"image-id\"); for logs run: kubectl -n foo logs pod -c step-failure\n", }}, }, @@ -245,7 +245,7 @@ func TestMakeTaskRunStatus(t *testing.T) { Conditions: []apis.Condition{{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonFailed, + Reason: v1beta1.TaskRunSucceededReasonFailed.String(), Message: "boom", }}, }, @@ -276,7 +276,7 @@ func TestMakeTaskRunStatus(t *testing.T) { Conditions: []apis.Condition{{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonFailed, + Reason: v1beta1.TaskRunSucceededReasonFailed.String(), Message: "OOMKilled", }}, }, @@ -304,7 +304,7 @@ func TestMakeTaskRunStatus(t *testing.T) { Conditions: []apis.Condition{{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonFailed, + Reason: v1beta1.TaskRunSucceededReasonFailed.String(), Message: "build failed for unspecified reasons.", }}, }, @@ -652,7 +652,7 @@ func TestMakeTaskRunStatus(t *testing.T) { Conditions: []apis.Condition{{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonFailed, + Reason: v1beta1.TaskRunSucceededReasonFailed.String(), Message: "\"step-non-json\" exited with code 1 (image: \"image\"); for logs run: kubectl -n foo logs pod -c step-non-json\n", }}, }, diff --git a/pkg/reconciler/events/cloudevent/cloudevent.go b/pkg/reconciler/events/cloudevent/cloudevent.go index 780fce0879b..c72b9b20e45 100644 --- a/pkg/reconciler/events/cloudevent/cloudevent.go +++ b/pkg/reconciler/events/cloudevent/cloudevent.go @@ -134,14 +134,25 @@ func getEventType(runObject v1beta1.RunsToCompletion) (*TektonEventType, error) var eventType TektonEventType switch { case c.IsUnknown(): - // TBD We should have different event types here, e.g. started, running - // That requires having either knowledge about the previous condition or - // TaskRun and PipelineRun using dedicated "Reasons" or "Conditions" switch t.Kind { case "TaskRun": - eventType = TektonTaskRunUnknownV1 + switch c.Reason { + case v1beta1.TaskRunSucceededReasonStarted.String(): + eventType = TektonTaskRunStartedV1 + case v1beta1.TaskRunSucceededReasonRunning.String(): + eventType = TektonTaskRunRunningV1 + default: + eventType = TektonTaskRunUnknownV1 + } case "PipelineRun": - eventType = TektonPipelineRunUnknownV1 + switch c.Reason { + case v1beta1.PipelineRunSucceededReasonStarted.String(): + eventType = TektonPipelineRunStartedV1 + case v1beta1.PipelineRunSucceededReasonRunning.String(): + eventType = TektonPipelineRunRunningV1 + default: + eventType = TektonPipelineRunUnknownV1 + } } case c.IsFalse(): switch t.Kind { diff --git a/pkg/reconciler/events/cloudevent/cloudevent_test.go b/pkg/reconciler/events/cloudevent/cloudevent_test.go index ddeff54c82c..c72a2e79197 100644 --- a/pkg/reconciler/events/cloudevent/cloudevent_test.go +++ b/pkg/reconciler/events/cloudevent/cloudevent_test.go @@ -35,7 +35,7 @@ const ( pipelineRunName = "fakepipelinerunname" ) -func getTaskRunByCondition(status corev1.ConditionStatus) *v1beta1.TaskRun { +func getTaskRunByCondition(status corev1.ConditionStatus, reason string) *v1beta1.TaskRun { return &v1beta1.TaskRun{ TypeMeta: metav1.TypeMeta{ Kind: "TaskRun", @@ -52,13 +52,14 @@ func getTaskRunByCondition(status corev1.ConditionStatus) *v1beta1.TaskRun { Conditions: []apis.Condition{{ Type: apis.ConditionSucceeded, Status: status, + Reason: reason, }}, }, }, } } -func getPipelineRunByCondition(status corev1.ConditionStatus) *v1beta1.PipelineRun { +func getPipelineRunByCondition(status corev1.ConditionStatus, reason string) *v1beta1.PipelineRun { return &v1beta1.PipelineRun{ TypeMeta: metav1.TypeMeta{ Kind: "PipelineRun", @@ -75,6 +76,7 @@ func getPipelineRunByCondition(status corev1.ConditionStatus) *v1beta1.PipelineR Conditions: []apis.Condition{{ Type: apis.ConditionSucceeded, Status: status, + Reason: reason, }}, }, }, @@ -87,17 +89,25 @@ func TestEventForTaskRun(t *testing.T) { taskRun *v1beta1.TaskRun wantEventType TektonEventType }{{ + desc: "send a cloud event when a taskrun starts", + taskRun: getTaskRunByCondition(corev1.ConditionUnknown, v1beta1.TaskRunSucceededReasonStarted.String()), + wantEventType: TektonTaskRunStartedV1, + }, { + desc: "send a cloud event when a taskrun starts running", + taskRun: getTaskRunByCondition(corev1.ConditionUnknown, v1beta1.TaskRunSucceededReasonRunning.String()), + wantEventType: TektonTaskRunRunningV1, + }, { desc: "send a cloud event with unknown status taskrun", - taskRun: getTaskRunByCondition(corev1.ConditionUnknown), + taskRun: getTaskRunByCondition(corev1.ConditionUnknown, "doesn't matter"), wantEventType: TektonTaskRunUnknownV1, + }, { + desc: "send a cloud event with failed status taskrun", + taskRun: getTaskRunByCondition(corev1.ConditionFalse, "meh"), + wantEventType: TektonTaskRunFailedV1, }, { desc: "send a cloud event with successful status taskrun", - taskRun: getTaskRunByCondition(corev1.ConditionTrue), + taskRun: getTaskRunByCondition(corev1.ConditionTrue, "yay"), wantEventType: TektonTaskRunSuccessfulV1, - }, { - desc: "send a cloud event with unknown status taskrun", - taskRun: getTaskRunByCondition(corev1.ConditionFalse), - wantEventType: TektonTaskRunFailedV1, }} { t.Run(c.desc, func(t *testing.T) { names.TestingSeed() @@ -136,16 +146,24 @@ func TestEventForPipelineRun(t *testing.T) { pipelineRun *v1beta1.PipelineRun wantEventType TektonEventType }{{ - desc: "send a cloud event with unknown status taskrun", - pipelineRun: getPipelineRunByCondition(corev1.ConditionUnknown), + desc: "send a cloud event with unknown status pipelinerun, just started", + pipelineRun: getPipelineRunByCondition(corev1.ConditionUnknown, v1beta1.PipelineRunSucceededReasonStarted.String()), + wantEventType: TektonPipelineRunStartedV1, + }, { + desc: "send a cloud event with unknown status pipelinerun, just started running", + pipelineRun: getPipelineRunByCondition(corev1.ConditionUnknown, v1beta1.PipelineRunSucceededReasonRunning.String()), + wantEventType: TektonPipelineRunRunningV1, + }, { + desc: "send a cloud event with unknown status pipelinerun", + pipelineRun: getPipelineRunByCondition(corev1.ConditionUnknown, "doesn't matter"), wantEventType: TektonPipelineRunUnknownV1, }, { - desc: "send a cloud event with successful status taskrun", - pipelineRun: getPipelineRunByCondition(corev1.ConditionTrue), + desc: "send a cloud event with successful status pipelinerun", + pipelineRun: getPipelineRunByCondition(corev1.ConditionTrue, "yay"), wantEventType: TektonPipelineRunSuccessfulV1, }, { - desc: "send a cloud event with unknown status taskrun", - pipelineRun: getPipelineRunByCondition(corev1.ConditionFalse), + desc: "send a cloud event with unknown status pipelinerun", + pipelineRun: getPipelineRunByCondition(corev1.ConditionFalse, "meh"), wantEventType: TektonPipelineRunFailedV1, }} { t.Run(c.desc, func(t *testing.T) { diff --git a/pkg/reconciler/pipelinerun/pipelinerun.go b/pkg/reconciler/pipelinerun/pipelinerun.go index 43d9d621683..e8409cad7ea 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun.go +++ b/pkg/reconciler/pipelinerun/pipelinerun.go @@ -94,10 +94,6 @@ const ( // pipelineRunAgentName defines logging agent name for PipelineRun Controller pipelineRunAgentName = "pipeline-controller" - - // Event reasons - eventReasonFailed = "PipelineRunFailed" - eventReasonSucceeded = "PipelineRunSucceeded" ) type configStore interface { @@ -203,7 +199,7 @@ func (c *Reconciler) Reconcile(ctx context.Context, key string) error { default: if err := c.tracker.Track(pr.GetTaskRunRef(), pr); err != nil { c.Logger.Errorf("Failed to create tracker for TaskRuns for PipelineRun %s: %v", pr.Name, err) - c.Recorder.Event(pr, corev1.EventTypeWarning, eventReasonFailed, "Failed to create tracker for TaskRuns for PipelineRun") + c.Recorder.Event(pr, corev1.EventTypeWarning, v1beta1.PipelineRunSucceededReasonFailed.String(), "Failed to create tracker for TaskRuns for PipelineRun") return err } @@ -227,7 +223,7 @@ func (c *Reconciler) Reconcile(ctx context.Context, key string) error { if !equality.Semantic.DeepEqual(original.Status, pr.Status) { if _, err := c.updateStatus(pr); err != nil { c.Logger.Warn("Failed to update PipelineRun status", zap.Error(err)) - c.Recorder.Event(pr, corev1.EventTypeWarning, eventReasonFailed, "PipelineRun failed to update") + c.Recorder.Event(pr, corev1.EventTypeWarning, v1beta1.PipelineRunSucceededReasonFailed.String(), "PipelineRun failed to update") return multierror.Append(merr, err) } updated = true @@ -240,7 +236,7 @@ func (c *Reconciler) Reconcile(ctx context.Context, key string) error { if !reflect.DeepEqual(original.ObjectMeta.Labels, pr.ObjectMeta.Labels) || !reflect.DeepEqual(original.ObjectMeta.Annotations, pr.ObjectMeta.Annotations) { if _, err := c.updateLabelsAndAnnotations(pr); err != nil { c.Logger.Warn("Failed to update PipelineRun labels/annotations", zap.Error(err)) - c.Recorder.Event(pr, corev1.EventTypeWarning, eventReasonFailed, "PipelineRun failed to update labels/annotations") + c.Recorder.Event(pr, corev1.EventTypeWarning, v1beta1.PipelineRunSucceededReasonFailed.String(), "PipelineRun failed to update labels/annotations") return multierror.Append(merr, err) } updated = true @@ -533,7 +529,7 @@ func (c *Reconciler) reconcile(ctx context.Context, pr *v1beta1.PipelineRun) err if pipelineState.IsDone() && pr.IsDone() { c.timeoutHandler.Release(pr) - c.Recorder.Event(pr, corev1.EventTypeNormal, eventReasonSucceeded, "PipelineRun completed successfully.") + c.Recorder.Event(pr, corev1.EventTypeNormal, v1beta1.PipelineRunSucceededReasonSuccessful.String(), "PipelineRun completed successfully.") return nil } diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go index ad5910b7473..b2c936d1402 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun_test.go +++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go @@ -275,8 +275,8 @@ func TestReconcile(t *testing.T) { if condition == nil || condition.Status != corev1.ConditionUnknown { t.Errorf("Expected PipelineRun status to be in progress, but was %v", condition) } - if condition != nil && condition.Reason != resources.ReasonRunning { - t.Errorf("Expected reason %q but was %s", resources.ReasonRunning, condition.Reason) + if condition != nil && condition.Reason != v1beta1.PipelineRunSucceededReasonRunning.String() { + t.Errorf("Expected reason %q but was %s", v1beta1.PipelineRunSucceededReasonRunning.String(), condition.Reason) } if len(reconciledRun.Status.TaskRuns) != 2 { @@ -777,7 +777,7 @@ func TestReconcileOnCompletedPipelineRun(t *testing.T) { tb.PipelineRunStatus(tb.PipelineRunStatusCondition(apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionTrue, - Reason: resources.ReasonSucceeded, + Reason: v1beta1.PipelineRunSucceededReasonSuccessful.String(), Message: "All Tasks have completed executing", }), tb.PipelineRunTaskRunsStatus(taskRunName, &v1beta1.PipelineRunTaskRunStatus{ @@ -962,7 +962,7 @@ func TestReconcileWithTimeout(t *testing.T) { } // The PipelineRun should be timed out. - if reconciledRun.Status.GetCondition(apis.ConditionSucceeded).Reason != resources.ReasonTimedOut { + if reconciledRun.Status.GetCondition(apis.ConditionSucceeded).Reason != v1beta1.PipelineRunSucceededReasonTimedOut.String() { t.Errorf("Expected PipelineRun to be timed out, but condition reason is %s", reconciledRun.Status.GetCondition(apis.ConditionSucceeded)) } @@ -1646,7 +1646,7 @@ func TestReconcileWithFailingConditionChecks(t *testing.T) { tb.PipelineRunStatus(tb.PipelineRunStatusCondition(apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionUnknown, - Reason: resources.ReasonRunning, + Reason: v1beta1.PipelineRunSucceededReasonRunning.String(), Message: "Not all Tasks in the Pipeline have finished executing", }), tb.PipelineRunTaskRunsStatus(pipelineRunName+"task-1", &v1beta1.PipelineRunTaskRunStatus{ PipelineTaskName: "task-1", diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go index 20b0609b597..cb8b082cf7b 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go @@ -37,28 +37,6 @@ import ( ) const ( - // ReasonRunning indicates that the reason for the inprogress status is that the TaskRun - // is just starting to be reconciled - ReasonRunning = "Running" - - // ReasonFailed indicates that the reason for the failure status is that one of the TaskRuns failed - ReasonFailed = "Failed" - - // ReasonCancelled indicates that the reason for the cancelled status is that one of the TaskRuns cancelled - ReasonCancelled = "Cancelled" - - // ReasonSucceeded indicates that the reason for the finished status is that all of the TaskRuns - // completed successfully - ReasonSucceeded = "Succeeded" - - // ReasonCompleted indicates that the reason for the finished status is that all of the TaskRuns - // completed successfully but with some conditions checking failed - ReasonCompleted = "Completed" - - // ReasonTimedOut indicates that the PipelineRun has taken longer than its configured - // timeout - ReasonTimedOut = "PipelineRunTimeout" - // ReasonConditionCheckFailed indicates that the reason for the failure status is that the // condition check associated to the pipeline task evaluated to false ReasonConditionCheckFailed = "ConditionCheckFailed" @@ -74,6 +52,7 @@ func (e *TaskNotFoundError) Error() string { return fmt.Sprintf("Couldn't retrieve Task %q: %s", e.Name, e.Msg) } +// ConditionNotFoundError is used to track failures to the type ConditionNotFoundError struct { Name string Msg string @@ -145,7 +124,7 @@ func (t ResolvedPipelineRunTask) IsCancelled() bool { return false } - return c.IsFalse() && c.Reason == v1beta1.TaskRunSpecStatusCancelled + return c.IsFalse() && c.Reason == v1beta1.TaskRunSucceededReasonCancelled.String() } // ToMap returns a map that maps pipeline task name to the resolved pipeline run task @@ -192,7 +171,7 @@ func (state PipelineRunState) GetNextTasks(candidateTasks map[string]struct{}) [ if _, ok := candidateTasks[t.PipelineTask.Name]; ok && t.TaskRun != nil { status := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) if status != nil && status.IsFalse() { - if !(t.TaskRun.IsCancelled() || status.Reason == v1beta1.TaskRunSpecStatusCancelled || status.Reason == ReasonConditionCheckFailed) { + if !(t.TaskRun.IsCancelled() || status.Reason == v1beta1.TaskRunSucceededReasonCancelled.String() || status.Reason == ReasonConditionCheckFailed) { if len(t.TaskRun.Status.RetriesStatus) < t.PipelineTask.Retries { tasks = append(tasks, t) } @@ -417,7 +396,7 @@ func GetPipelineConditionStatus(pr *v1beta1.PipelineRun, state PipelineRunState, return &apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonTimedOut, + Reason: v1beta1.PipelineRunSucceededReasonTimedOut.String(), Message: fmt.Sprintf("PipelineRun %q failed to finish within %q", pr.Name, pr.Spec.Timeout.Duration.String()), } } @@ -429,7 +408,7 @@ func GetPipelineConditionStatus(pr *v1beta1.PipelineRun, state PipelineRunState, return &apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonCancelled, + Reason: v1beta1.PipelineRunSucceededReasonCancelled.String(), Message: fmt.Sprintf("TaskRun %s has cancelled", rprt.TaskRun.Name), } } @@ -439,7 +418,7 @@ func GetPipelineConditionStatus(pr *v1beta1.PipelineRun, state PipelineRunState, return &apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionFalse, - Reason: ReasonFailed, + Reason: v1beta1.PipelineRunSucceededReasonFailed.String(), Message: fmt.Sprintf("TaskRun %s has failed", rprt.TaskRun.Name), } } @@ -463,9 +442,9 @@ func GetPipelineConditionStatus(pr *v1beta1.PipelineRun, state PipelineRunState, if reflect.DeepEqual(allTasks, successOrSkipTasks) { logger.Infof("All TaskRuns have finished for PipelineRun %s so it has finished", pr.Name) - reason := ReasonSucceeded + reason := v1beta1.PipelineRunSucceededReasonSuccessful.String() if skipTasks != 0 { - reason = ReasonCompleted + reason = v1beta1.PipelineRunSucceededReasonCompleted.String() } return &apis.Condition{ @@ -481,7 +460,7 @@ func GetPipelineConditionStatus(pr *v1beta1.PipelineRun, state PipelineRunState, return &apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionUnknown, - Reason: ReasonRunning, + Reason: v1beta1.PipelineRunSucceededReasonRunning.String(), Message: fmt.Sprintf("Tasks Completed: %d, Incomplete: %d, Skipped: %d", len(successOrSkipTasks)-skipTasks, len(allTasks)-len(successOrSkipTasks), skipTasks), } } diff --git a/pkg/reconciler/reconciler_test.go b/pkg/reconciler/reconciler_test.go index 8367d577852..a132d516345 100644 --- a/pkg/reconciler/reconciler_test.go +++ b/pkg/reconciler/reconciler_test.go @@ -25,7 +25,6 @@ import ( tb "github.com/tektoncd/pipeline/internal/builder/v1beta1" "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - "github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun/resources" ttesting "github.com/tektoncd/pipeline/pkg/reconciler/testing" test "github.com/tektoncd/pipeline/test" "go.uber.org/zap" @@ -43,7 +42,7 @@ func TestRecorderOptions(t *testing.T) { tb.PipelineRunStatus(tb.PipelineRunStatusCondition(apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionTrue, - Reason: resources.ReasonSucceeded, + Reason: v1beta1.PipelineRunSucceededReasonSuccessful.String(), Message: "All Tasks have completed executing", })), )} diff --git a/pkg/reconciler/taskrun/taskrun.go b/pkg/reconciler/taskrun/taskrun.go index 7636ba71189..e0514ff11f8 100644 --- a/pkg/reconciler/taskrun/taskrun.go +++ b/pkg/reconciler/taskrun/taskrun.go @@ -172,7 +172,7 @@ func (c *Reconciler) Reconcile(ctx context.Context, key string) error { if tr.IsCancelled() { before := tr.Status.GetCondition(apis.ConditionSucceeded) message := fmt.Sprintf("TaskRun %q was cancelled", tr.Name) - err := c.failTaskRun(tr, v1beta1.TaskRunReasonCancelled, message) + err := c.failTaskRun(tr, v1beta1.TaskRunSucceededReasonCancelled, message) return c.finishReconcileUpdateEmitEvents(tr, original, before, err) } @@ -181,7 +181,7 @@ func (c *Reconciler) Reconcile(ctx context.Context, key string) error { if tr.HasTimedOut() { before := tr.Status.GetCondition(apis.ConditionSucceeded) message := fmt.Sprintf("TaskRun %q failed to finish within %q", tr.Name, tr.GetTimeout()) - err := c.failTaskRun(tr, podconvert.ReasonTimedOut, message) + err := c.failTaskRun(tr, v1beta1.TaskRunSucceededReasonTimedOut, message) return c.finishReconcileUpdateEmitEvents(tr, original, before, err) } @@ -506,9 +506,9 @@ func (c *Reconciler) handlePodCreationError(tr *v1beta1.TaskRun, err error) { // If a pod is associated to the TaskRun, it stops it // failTaskRun function may return an error in case the pod could not be deleted // failTaskRun may update the local TaskRun status, but it won't push the updates to etcd -func (c *Reconciler) failTaskRun(tr *v1beta1.TaskRun, reason, message string) error { +func (c *Reconciler) failTaskRun(tr *v1beta1.TaskRun, reason v1beta1.TaskRunSucceededReason, message string) error { - c.Logger.Warn("stopping task run %q because of %q", tr.Name, reason) + c.Logger.Warn("stopping task run %q because of %q", tr.Name, reason.String()) tr.Status.MarkResourceFailed(reason, errors.New(message)) // update tr completed time diff --git a/pkg/reconciler/taskrun/taskrun_test.go b/pkg/reconciler/taskrun/taskrun_test.go index c66d7a60f7f..857359230a7 100644 --- a/pkg/reconciler/taskrun/taskrun_test.go +++ b/pkg/reconciler/taskrun/taskrun_test.go @@ -452,8 +452,8 @@ func TestReconcile_ExplicitDefaultSA(t *testing.T) { if condition == nil || condition.Status != corev1.ConditionUnknown { t.Errorf("Expected invalid TaskRun to have in progress status, but had %v", condition) } - if condition != nil && condition.Reason != podconvert.ReasonRunning { - t.Errorf("Expected reason %q but was %s", podconvert.ReasonRunning, condition.Reason) + if condition != nil && condition.Reason != v1beta1.TaskRunSucceededReasonRunning.String() { + t.Errorf("Expected reason %q but was %s", v1beta1.TaskRunSucceededReasonRunning.String(), condition.Reason) } if tr.Status.PodName == "" { @@ -1080,8 +1080,8 @@ func TestReconcile(t *testing.T) { if condition == nil || condition.Status != corev1.ConditionUnknown { t.Errorf("Expected invalid TaskRun to have in progress status, but had %v", condition) } - if condition != nil && condition.Reason != podconvert.ReasonRunning { - t.Errorf("Expected reason %q but was %s", podconvert.ReasonRunning, condition.Reason) + if condition != nil && condition.Reason != v1beta1.TaskRunSucceededReasonRunning.String() { + t.Errorf("Expected reason %q but was %s", v1beta1.TaskRunSucceededReasonRunning.String(), condition.Reason) } if tr.Status.PodName == "" { @@ -1401,7 +1401,7 @@ func TestReconcilePodUpdateStatus(t *testing.T) { if d := cmp.Diff(&apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionUnknown, - Reason: "Running", + Reason: v1beta1.TaskRunSucceededReasonRunning.String(), Message: "Not all Steps in the Task have finished executing", }, newTr.Status.GetCondition(apis.ConditionSucceeded), ignoreLastTransitionTime); d != "" { t.Fatalf("Did not get expected condition %s", diff.PrintWantGot(d)) @@ -1425,7 +1425,7 @@ func TestReconcilePodUpdateStatus(t *testing.T) { if d := cmp.Diff(&apis.Condition{ Type: apis.ConditionSucceeded, Status: corev1.ConditionTrue, - Reason: podconvert.ReasonSucceeded, + Reason: v1beta1.TaskRunSucceededReasonSuccessful.String(), Message: "All Steps have completed executing", }, newTr.Status.GetCondition(apis.ConditionSucceeded), ignoreLastTransitionTime); d != "" { t.Errorf("Did not get expected condition %s", diff.PrintWantGot(d)) @@ -2428,7 +2428,7 @@ func TestFailTaskRun(t *testing.T) { name string taskRun *v1beta1.TaskRun pod *corev1.Pod - reason string + reason v1beta1.TaskRunSucceededReason message string expectedStatus apis.Condition }{{