Skip to content

Commit

Permalink
Add the imageID for each step to the TaskRun.Spec.Status object.
Browse files Browse the repository at this point in the history
This allows users to trace the exact steps (including digest) used in each TaskRun.
This information is already available on a Pod, but we need to assume completed Pods
will be GC'ed and not available long after the run is complete.
  • Loading branch information
dlorenc committed Aug 12, 2019
1 parent 5138955 commit 01d5e07
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 5 deletions.
33 changes: 33 additions & 0 deletions docs/taskruns.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ A `TaskRun` runs until all `steps` have completed or until a failure occurs.
- [Service Account](#service-account)
- [Pod Template](#pod-template)
- [Steps](#steps)
- [Status](#status)
- [Cancelling a TaskRun](#cancelling-a-taskrun)
- [Examples](#examples)
- [Sidecars](#sidecars)
Expand Down Expand Up @@ -307,6 +308,38 @@ If multiple `steps` are defined in the `Task` invoked by the `TaskRun`, we will
`spec.steps` of the `Task`, when the `TaskRun` is accessed by the `get` command, e.g.
`kubectl get taskrun <name> -o yaml`. Replace \<name\> with the name of the `TaskRun`.

## Status

As a TaskRun completes, it's `status` field is filled in with relevant information for
the overall run, as well as each step.

The following example shows a completed TaskRun and it's `status` field:

```yaml
completionTime: "2019-08-12T18:22:57Z"
conditions:
- lastTransitionTime: "2019-08-12T18:22:57Z"
message: All Steps have completed executing
reason: Succeeded
status: "True"
type: Succeeded
podName: status-taskrun-pod-6488ef
startTime: "2019-08-12T18:22:51Z"
steps:
- container: step-hello
imageID: docker-pullable://busybox@sha256:895ab622e92e18d6b461d671081757af7dbaa3b00e3e28e12505af7817f73649
name: hello
terminated:
containerID: docker://d5a54f5bbb8e7a6fd3bc7761b78410403244cf4c9c5822087fb0209bf59e3621
exitCode: 0
finishedAt: "2019-08-12T18:22:56Z"
reason: Completed
startedAt: "2019-08-12T18:22:54Z"
```

Fields include start and stop times for the `TaskRun` and each `Step`, and exit codes.
For each step we also include the fully-qualified image used, with the digest.

## Cancelling a TaskRun

In order to cancel a running task (`TaskRun`), you need to update its spec to
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/pipeline/v1alpha1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ type StepState struct {
corev1.ContainerState
Name string `json:"name,omitempty"`
ContainerName string `json:"container,omitempty"`
ImageID string `json:"imageID,omitempty"`
}

// CloudEventDelivery is the target of a cloud event along with the state of
Expand Down
1 change: 1 addition & 0 deletions pkg/status/taskrunpod.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func UpdateStatusFromPod(taskRun *v1alpha1.TaskRun, pod *corev1.Pod, resourceLis
ContainerState: *s.State.DeepCopy(),
Name: resources.TrimContainerNamePrefix(s.Name),
ContainerName: s.Name,
ImageID: s.ImageID,
})
}
}
Expand Down
17 changes: 14 additions & 3 deletions pkg/status/taskrunpod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ func TestUpdateStatusFromPod(t *testing.T) {
podStatus: corev1.PodStatus{
InitContainerStatuses: []corev1.ContainerStatus{{
// creds-init; ignored
ImageID: "ignored",
}},
ContainerStatuses: []corev1.ContainerStatus{{
Name: "step-state-name",
Name: "step-state-name",
ImageID: "",
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
ExitCode: 123,
Expand All @@ -102,11 +104,14 @@ func TestUpdateStatusFromPod(t *testing.T) {
podStatus: corev1.PodStatus{
InitContainerStatuses: []corev1.ContainerStatus{{
// creds-init; ignored.
ImageID: "ignoreme",
}, {
// git-init; ignored.
ImageID: "ignoreme",
}},
ContainerStatuses: []corev1.ContainerStatus{{
Name: "step-state-name",
Name: "step-state-name",
ImageID: "image-id",
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
ExitCode: 123,
Expand All @@ -125,6 +130,7 @@ func TestUpdateStatusFromPod(t *testing.T) {
}},
Name: "state-name",
ContainerName: "step-state-name",
ImageID: "image-id",
}},
},
}, {
Expand All @@ -138,6 +144,7 @@ func TestUpdateStatusFromPod(t *testing.T) {
ExitCode: 0,
},
},
ImageID: "image-id",
}},
},
want: v1alpha1.TaskRunStatus{
Expand All @@ -151,6 +158,7 @@ func TestUpdateStatusFromPod(t *testing.T) {
}},
Name: "step-push",
ContainerName: "step-step-push",
ImageID: "image-id",
}},
// We don't actually care about the time, just that it's not nil
CompletionTime: &metav1.Time{Time: time.Now()},
Expand Down Expand Up @@ -181,9 +189,10 @@ func TestUpdateStatusFromPod(t *testing.T) {
}, {
desc: "failure-terminated",
podStatus: corev1.PodStatus{
Phase: corev1.PodFailed,
Phase: corev1.PodFailed,
InitContainerStatuses: []corev1.ContainerStatus{{
// creds-init status; ignored
ImageID: "ignore-me",
}},
ContainerStatuses: []corev1.ContainerStatus{{
Name: "step-failure",
Expand All @@ -209,8 +218,10 @@ func TestUpdateStatusFromPod(t *testing.T) {
Terminated: &corev1.ContainerStateTerminated{
ExitCode: 123,
}},

Name: "failure",
ContainerName: "step-failure",
ImageID: "image-id",
}},
// We don't actually care about the time, just that it's not nil
CompletionTime: &metav1.Time{Time: time.Now()},
Expand Down
66 changes: 64 additions & 2 deletions test/taskrun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ limitations under the License.
package test

import (
"fmt"
"testing"

"github.com/ghodss/yaml"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
Expand Down Expand Up @@ -99,8 +102,67 @@ func TestTaskRunFailure(t *testing.T) {
Name: "world",
ContainerName: "step-world",
}}
ignoreFields := cmpopts.IgnoreFields(corev1.ContainerStateTerminated{}, "StartedAt", "FinishedAt", "ContainerID")
if d := cmp.Diff(taskrun.Status.Steps, expectedStepState, ignoreFields); d != "" {
ignoreTerminatedFields := cmpopts.IgnoreFields(corev1.ContainerStateTerminated{}, "StartedAt", "FinishedAt", "ContainerID")
ignoreStepFields := cmpopts.IgnoreFields(v1alpha1.StepState{}, "ImageID")
if d := cmp.Diff(taskrun.Status.Steps, expectedStepState, ignoreTerminatedFields, ignoreStepFields); d != "" {
t.Fatalf("-got, +want: %v", d)
}
}

func TestTaskRunStatus(t *testing.T) {
c, namespace := setup(t)
t.Parallel()

knativetest.CleanupOnInterrupt(func() { tearDown(t, c, namespace) }, t.Logf)
defer tearDown(t, c, namespace)

taskRunName := "status-taskrun"

fqImageName := "busybox@sha256:895ab622e92e18d6b461d671081757af7dbaa3b00e3e28e12505af7817f73649"
t.Logf("Creating Task and TaskRun in namespace %s", namespace)
task := tb.Task("status-task", namespace, tb.TaskSpec(
// This was the digest of the latest tag as of 8/12/2019
tb.Step("hello", "busybox@sha256:895ab622e92e18d6b461d671081757af7dbaa3b00e3e28e12505af7817f73649",
tb.Command("/bin/sh"), tb.Args("-c", "echo hello"),
),
))
if _, err := c.TaskClient.Create(task); err != nil {
t.Fatalf("Failed to create Task: %s", err)
}
taskRun := tb.TaskRun(taskRunName, namespace, tb.TaskRunSpec(
tb.TaskRunTaskRef("status-task"),
))
if _, err := c.TaskRunClient.Create(taskRun); err != nil {
t.Fatalf("Failed to create TaskRun: %s", err)
}

t.Logf("Waiting for TaskRun in namespace %s to fail", namespace)
if err := WaitForTaskRunState(c, taskRunName, TaskRunSucceed(taskRunName), "TaskRunSucceed"); err != nil {
t.Errorf("Error waiting for TaskRun to finish: %s", err)
}

taskrun, err := c.TaskRunClient.Get(taskRunName, metav1.GetOptions{})
if err != nil {
t.Fatalf("Couldn't get expected TaskRun %s: %s", taskRunName, err)
}

expectedStepState := []v1alpha1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
ExitCode: 0,
Reason: "Completed",
},
},
Name: "hello",
ContainerName: "step-hello",
ImageID: "docker-pullable://" + fqImageName,
}}

b, _ := yaml.Marshal(taskrun.Status)
fmt.Println(string(b))

ignoreTerminatedFields := cmpopts.IgnoreFields(corev1.ContainerStateTerminated{}, "StartedAt", "FinishedAt", "ContainerID")
if d := cmp.Diff(taskrun.Status.Steps, expectedStepState, ignoreTerminatedFields); d != "" {
t.Fatalf("-got, +want: %v", d)
}
}

0 comments on commit 01d5e07

Please sign in to comment.