tektoncd / pipeline

A cloud-native Pipeline resource.
https://tekton.dev
Apache License 2.0
8.51k stars 1.78k forks source link

Dependent Task after Task with when condition are skipped #7680

Open Allda opened 9 months ago

Allda commented 9 months ago

Expected Behavior

Hello, I am building a pipeline with a conditional series of tasks that use the same when condition, after that series of tasks there is one or more other tasks that don't have the condition.

Simplified task schema looks like this

A -> B -> C

where A and B use the condition given by the pipeline argument. At the same time, B uses the output of A as an input parameter.

I expect the C is triggered regardless of A or B but as shown bellow this is no the case and if A and B are skipped the C is also skipped.

Actual Behavior

Based on the pipeline argument A and B are skipped as expected, but C is also skipped which is unexpected. Skipped reasons are the following: A - When Expressions evaluated to false B - Results were missing < -- This task uses when and should be also skipped the same way as task A C - Parent Tasks were skipped

Steps to Reproduce the Problem

  1. Create the following task and pipeline

    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
    name: basic-task
    spec:
    params:
    - default: Hello
      name: appName
      type: string
    results:
    - name: my-result
      type: string
    steps:
    - image: registry.redhat.io/ubi7/ubi-minimal
      name: ''
      resources: {}
      script: |
    
        echo $(inputs.params.appName)
    
        echo $(inputs.params.appName) > $(results.my-result.path)
    
    apiVersion: tekton.dev/v1beta1
    kind: Pipeline
    metadata:
    name: when
    spec:
    params:
    - default: foo
      name: param1
      type: string
    tasks:
    - name: basic-task
      params:
        - name: appName
          value: Hello
      taskRef:
        kind: Task
        name: basic-task
      when:
        - input: $(params.param1)
          operator: in
          values:
            - bar
    - name: basic-task-2
      params:
        - name: appName
          value: $(tasks.basic-task.results.my-result)
      runAfter:
        - basic-task
      taskRef:
        kind: Task
        name: basic-task
      when:
        - input: $(params.param1)
          operator: in
          values:
            - bar
    - name: basic-task-3
      params:
        - name: appName
          value: Hello
      runAfter:
        - basic-task-2
      taskRef:
        kind: Task
        name: basic-task

3. Execute pipeline with default params
4.

# Additional Info
Client Version: 4.14.6
Kustomize Version: v5.0.1
Server Version: 4.13.31
Kubernetes Version: v1.26.13+77e61a2

- Tekton Pipeline version:

Client version: 0.33.0
Chains version: v0.16.1
Pipeline version: v0.47.6
Triggers version: v0.24.2
Operator version: v0.67.3

<!-- Any other additional information -->
l-qing commented 9 months ago

I once encountered a similar problem, and I suspect it is related to the status "Results were missing" in Phase B. After all, after skipping Phase A, Phase B still made a judgment on whether to execute.

l-qing commented 9 months ago

I'm not sure if this behavior is by design or a bug.

Relevant code:

https://github.com/tektoncd/pipeline/blob/123f4a211df298ac28dc18df2ec58701c9ffe842/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go#L306-L319

https://github.com/tektoncd/pipeline/blob/123f4a211df298ac28dc18df2ec58701c9ffe842/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go#L367-L388

https://github.com/tektoncd/pipeline/blob/123f4a211df298ac28dc18df2ec58701c9ffe842/pkg/apis/pipeline/v1/pipelinerun_types.go#L550-L565

AlanGreene commented 9 months ago

I think this is the relevant section of the docs on when expressions: https://tekton.dev/docs/pipelines/pipelines/#guarding-a-task-only

When when expressions evaluate to False, the Task will be skipped and:

  • The ordering-dependent Tasks will be executed
  • The resource-dependent Tasks (and their dependencies) will be skipped because of missing Results from the skipped parent Task.

Specifically the last point.

Also from the example just after that:

slack-msg will be skipped because it is missing the approver Result from manual-approval dependents of slack-msg would have been skipped too if it had any of them

As far as I understand this matches the behaviour you're describing so is working as designed.

Allda commented 9 months ago

I have spent last several days reading the documentation about how the conditional Tekton task works so I understand why this is happening, but on the other hand if a task depends on the previous one (B depends on A) and B is is not executed due to when condition should this be also blocking and skipping a rest of the pipeline? The missing results from A used in B as params are not needed because the B is skipped.

Would you happen to have any suggestions on how to workaround this? The usecase for this is when a pipeline contains a series of task that depends on each other and are controlled by input parameter. In such a case with a current behavior, the pipeline always skips the rest of the pipeline even though there are no missing data for dependencies.

Allda commented 9 months ago

@AlanGreene @l-qing Do you know if this issue can be workaround somehow until we get any official conclusion of this issue?

Allda commented 9 months ago

I checked the code briefly and I think moving skipBecauseWhenExpressionsEvaluatedToFalse higher in the switch hierarchy and giving it higher priority would resolve this issue. Is there any reason why it is below skipBecauseResultReferencesAreMissing and skipBecauseParentTaskWasSkipped ?

https://github.com/tektoncd/pipeline/blob/123f4a211df298ac28dc18df2ec58701c9ffe842/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go#L309-L332

willejs-ec commented 5 months ago

@Allda did you get anywhere with this? I think we are facing the same issue.

Allda commented 5 months ago

@willejs-ec Unfortunately I haven't. Due to this limitation, I wasn't able to use any when condition for tasks that have a common when condition and depend on each other. The only workaround I found was to put the condition inside of the task into the actual task code. This solution however makes the pipeline flow harder to read and forces a pipeline to create additional pods that are not doing any useful work and take resources and execution time.

jameshwc commented 2 months ago

We're facing the same issue.