Skip to content

Commit

Permalink
include taskrun failure message in logs
Browse files Browse the repository at this point in the history
  • Loading branch information
danielhelfand authored and tekton-robot committed Nov 26, 2019
1 parent bc480b6 commit 9e44d74
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 7 deletions.
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ k8s.io/kubernetes v1.13.3 h1:46t44D87wKtdKFgr/lXM60K8xPrW0wO67Woof3Vsv6E=
k8s.io/kubernetes v1.13.3/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
knative.dev/pkg v0.0.0-20190719141030-e4bc08cc8ded h1:CHn7mNgIE5GHMJqfNPFLBLcZlCdaTdQmAA8Uu6XLOKc=
knative.dev/pkg v0.0.0-20190719141030-e4bc08cc8ded/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
knative.dev/pkg v0.0.0-20191121191108-8c1fb5fe0446 h1:29XUTvB++mEHuZxVgx8+Wh3wqkzEspgfzMwsHPgw9Tk=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
1 change: 1 addition & 0 deletions pkg/cmd/taskrun/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,5 +184,6 @@ func hasFailed(tr *v1alpha1.TaskRun) string {
if tr.Status.Conditions[0].Status == corev1.ConditionFalse {
return tr.Status.Conditions[0].Message
}

return ""
}
30 changes: 25 additions & 5 deletions pkg/cmd/taskrun/log_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"knative.dev/pkg/apis/duck/v1beta1"
)

type step struct {
Expand Down Expand Up @@ -123,6 +124,11 @@ func (lr *LogReader) readAvailableLogs(tr *v1alpha1.TaskRun) (<-chan Log, <-chan
return nil, nil, fmt.Errorf("task %s has not started yet", lr.Task)
}

//Check if taskrun failed on start up
if err := hasTaskRunFailed(tr.Status.Conditions, lr.Task); err != nil {
return nil, nil, err
}

if tr.Status.PodName == "" {
return nil, nil, fmt.Errorf("pod for taskrun %s not available yet", tr.Name)
}
Expand Down Expand Up @@ -241,10 +247,10 @@ func getSteps(pod *corev1.Pod) []*step {
return steps
}

// reading of logs should wait untill the name of pod is
// updates in the status. Open a watch channel on run
// and keep checking the status until the pod name updatea
// or the timeout is reached
// Reading of logs should wait until the name of the pod is
// updated in the status. Open a watch channel on the task run
// and keep checking the status until the pod name updates
// or the timeout is reached.
func (lr *LogReader) waitUntilPodNameAvailable(timeout time.Duration) (*v1alpha1.TaskRun, error) {
var first = true
opts := metav1.ListOptions{
Expand Down Expand Up @@ -277,7 +283,21 @@ func (lr *LogReader) waitUntilPodNameAvailable(timeout time.Duration) (*v1alpha1
}
case <-time.After(timeout * time.Second):
watchRun.Stop()
return nil, fmt.Errorf("task %s create failed or has not started yet or pod for task not yet available", lr.Task)

//Check if taskrun failed on start up
if err = hasTaskRunFailed(run.Status.Conditions, lr.Task); err != nil {
return nil, err
}

return nil, fmt.Errorf("task %s create has not started yet or pod for task not yet available", lr.Task)
}
}
}

func hasTaskRunFailed(trConditions v1beta1.Conditions, taskName string) error {
if len(trConditions) != 0 && trConditions[0].Status == corev1.ConditionFalse {
return fmt.Errorf("task %s has failed: %s", taskName, trConditions[0].Message)
}

return nil
}
85 changes: 83 additions & 2 deletions pkg/cmd/taskrun/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/tektoncd/cli/pkg/test"
cb "github.com/tektoncd/cli/pkg/test/builder"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
"github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun/resources"
pipelinetest "github.com/tektoncd/pipeline/test"
tb "github.com/tektoncd/pipeline/test/builder"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -477,7 +478,7 @@ func TestLog_taskrun_follow_mode_no_pod_name(t *testing.T) {
t.Error("Expecting an error but it's empty")
}

expected := "task output-task create failed or has not started yet or pod for task not yet available"
expected := "task output-task create has not started yet or pod for task not yet available"
test.AssertOutput(t, expected, err.Error())
}

Expand Down Expand Up @@ -663,10 +664,90 @@ func TestLog_taskrun_follow_mode_update_timeout(t *testing.T) {
expectedOut := ""
test.AssertOutput(t, expectedOut, output)

expectedErr := "task output-task create failed or has not started yet or pod for task not yet available"
expectedErr := "task output-task create has not started yet or pod for task not yet available"
test.AssertOutput(t, expectedErr, err.Error())
}

func TestLog_taskrun_follow_mode_no_output_provided(t *testing.T) {
var (
prstart = clockwork.NewFakeClock()
ns = "namespace"
taskName = "output-task"
trName = "output-task-run"
trStartTime = prstart.Now().Add(20 * time.Second)
trPod = "output-task-pod-123456"
trStep1Name = "writefile-step"
trInitStep1 = "credential-initializer-mdzbr"
trInitStep2 = "place-tools"
nopStep = "nop"
)

trs := []*v1alpha1.TaskRun{
tb.TaskRun(trName, ns,
tb.TaskRunStatus(
tb.TaskRunStartTime(trStartTime),
tb.StatusCondition(apis.Condition{
Type: resources.ReasonFailed,
Status: corev1.ConditionFalse,
Message: "invalid output resources: TaskRun's declared resources didn't match usage in Task: Didn't provide required values: [builtImage]",
}),
tb.StepState(
cb.StepName(trStep1Name),
tb.StateTerminated(0),
),
tb.StepState(
cb.StepName(nopStep),
tb.StateTerminated(0),
),
),
tb.TaskRunSpec(
tb.TaskRunTaskRef(taskName),
),
),
}

nsList := []*corev1.Namespace{
{
ObjectMeta: metav1.ObjectMeta{
Name: "namespace",
},
},
}

p := []*corev1.Pod{
tb.Pod(trPod, ns,
tb.PodSpec(
tb.PodInitContainer(trInitStep1, "override-with-creds:latest"),
tb.PodInitContainer(trInitStep2, "override-with-tools:latest"),
tb.PodContainer(trStep1Name, trStep1Name+":latest"),
tb.PodContainer(nopStep, "override-with-nop:latest"),
),
cb.PodStatus(
cb.PodPhase(corev1.PodSucceeded),
cb.PodInitContainerStatus(trInitStep1, "override-with-creds:latest"),
cb.PodInitContainerStatus(trInitStep2, "override-with-tools:latest"),
),
),
}

logs := fake.Logs(
fake.Task(trPod),
)

cs, _ := test.SeedTestData(t, pipelinetest.Data{TaskRuns: trs, Pods: p, Namespaces: nsList})
watcher := watch.NewRaceFreeFake()
cs.Pipeline.PrependWatchReactor("taskruns", k8stest.DefaultWatchReactor(watcher, nil))
trlo := logOpts(trName, ns, cs, fake.Streamer(logs), false, true)

_, err := fetchLogs(trlo)
if err == nil {
t.Errorf("Expected error but no error occurred ")
}

expected := "task output-task has failed: invalid output resources: TaskRun's declared resources didn't match usage in Task: Didn't provide required values: [builtImage]"
test.AssertOutput(t, expected, err.Error())
}

func logOpts(run, ns string, cs pipelinetest.Clients, streamer stream.NewStreamerFunc, allSteps bool, follow bool) *LogOptions {
p := test.Params{
Kube: cs.Kube,
Expand Down

0 comments on commit 9e44d74

Please sign in to comment.