Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fail fast on invalid image #6982

Merged
merged 1 commit into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions pkg/reconciler/taskrun/taskrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,15 @@ type Reconciler struct {
tracerProvider trace.TracerProvider
}

// Check that our Reconciler implements taskrunreconciler.Interface
var (
// Check that our Reconciler implements taskrunreconciler.Interface
_ taskrunreconciler.Interface = (*Reconciler)(nil)

// Pod failure reasons that trigger failure of the TaskRun
podFailureReasons = map[string]struct{}{
"ImagePullBackOff": {},
"InvalidImageName": {},
}
)

// ReconcileKind compares the actual state with the desired, and attempts to
Expand Down Expand Up @@ -211,17 +217,21 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, tr *v1.TaskRun) pkgrecon

func (c *Reconciler) checkPodFailed(tr *v1.TaskRun) (bool, v1.TaskRunReason, string) {
for _, step := range tr.Status.Steps {
if step.Waiting != nil && step.Waiting.Reason == "ImagePullBackOff" {
image := step.ImageID
message := fmt.Sprintf(`The step %q in TaskRun %q failed to pull the image %q. The pod errored with the message: "%s."`, step.Name, tr.Name, image, step.Waiting.Message)
return true, v1.TaskRunReasonImagePullFailed, message
if step.Waiting != nil {
if _, found := podFailureReasons[step.Waiting.Reason]; found {
image := step.ImageID
message := fmt.Sprintf(`The step %q in TaskRun %q failed to pull the image %q. The pod errored with the message: "%s."`, step.Name, tr.Name, image, step.Waiting.Message)
return true, v1.TaskRunReasonImagePullFailed, message
}
}
}
for _, sidecar := range tr.Status.Sidecars {
if sidecar.Waiting != nil && sidecar.Waiting.Reason == "ImagePullBackOff" {
image := sidecar.ImageID
message := fmt.Sprintf(`The sidecar %q in TaskRun %q failed to pull the image %q. The pod errored with the message: "%s."`, sidecar.Name, tr.Name, image, sidecar.Waiting.Message)
return true, v1.TaskRunReasonImagePullFailed, message
if sidecar.Waiting != nil {
if _, found := podFailureReasons[sidecar.Waiting.Reason]; found {
image := sidecar.ImageID
message := fmt.Sprintf(`The sidecar %q in TaskRun %q failed to pull the image %q. The pod errored with the message: "%s."`, sidecar.Name, tr.Name, image, sidecar.Waiting.Message)
return true, v1.TaskRunReasonImagePullFailed, message
}
}
}
return false, "", ""
Expand Down
180 changes: 85 additions & 95 deletions pkg/reconciler/taskrun/taskrun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2314,65 +2314,36 @@ status:
}
}

func TestReconcilePodFailuresStepImagePullFailed(t *testing.T) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I turned the next test into a matrix test, and the two cases in here are included in the next test now.

taskRun := parse.MustParseV1TaskRun(t, `
metadata:
name: test-imagepull-fail
namespace: foo
spec:
taskSpec:
steps:
- image: whatever
status:
steps:
- container: step-unnamed-0
name: unnamed-0
imageID: whatever
waiting:
message: Back-off pulling image "whatever"
reason: ImagePullBackOff
taskSpec:
steps:
- image: whatever
`)
expectedStatus := &apis.Condition{
Type: apis.ConditionSucceeded,
Status: corev1.ConditionFalse,
Reason: "TaskRunImagePullFailed",
Message: `The step "unnamed-0" in TaskRun "test-imagepull-fail" failed to pull the image "whatever". The pod errored with the message: "Back-off pulling image "whatever"."`,
}

wantEvents := []string{
"Normal Started ",
`Warning Failed The step "unnamed-0" in TaskRun "test-imagepull-fail" failed to pull the image "whatever". The pod errored with the message: "Back-off pulling image "whatever".`,
}
d := test.Data{
TaskRuns: []*v1.TaskRun{taskRun},
}
testAssets, cancel := getTaskRunController(t, d)
defer cancel()
c := testAssets.Controller
clients := testAssets.Clients

if err := c.Reconciler.Reconcile(testAssets.Ctx, getRunName(taskRun)); err != nil {
t.Fatalf("Unexpected error when reconciling completed TaskRun : %v", err)
}
newTr, err := clients.Pipeline.TektonV1().TaskRuns(taskRun.Namespace).Get(testAssets.Ctx, taskRun.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("Expected completed TaskRun %s to exist but instead got error when getting it: %v", taskRun.Name, err)
}
condition := newTr.Status.GetCondition(apis.ConditionSucceeded)
if d := cmp.Diff(expectedStatus, condition, ignoreLastTransitionTime); d != "" {
t.Fatalf("Did not get expected condition %s", diff.PrintWantGot(d))
}
err = k8sevent.CheckEventsOrdered(t, testAssets.Recorder.Events, taskRun.Name, wantEvents)
if err != nil {
t.Errorf(err.Error())
}
}

func TestReconcilePodFailuresSidecarImagePullFailed(t *testing.T) {
taskRun := parse.MustParseV1TaskRun(t, `
func TestReconcilePodFailuresImageFailures(t *testing.T) {
var stepNumber int8
for _, tc := range []struct {
desc string
reason string
message string
failure string // "step" or "sidecar"
}{{
desc: "image pull failed sidecar",
reason: "ImagePullBackOff",
message: "Back-off pulling image \"whatever\"",
failure: "sidecar",
}, {
desc: "invalid image sidecar",
reason: "InvalidImageName",
message: "Invalid image \"whatever\"",
failure: "sidecar",
}, {
desc: "image pull failed step",
reason: "ImagePullBackOff",
message: "Back-off pulling image \"whatever\"",
failure: "step",
}, {
desc: "invalid image step",
reason: "InvalidImageName",
message: "Invalid image \"whatever\"",
failure: "step",
}} {
t.Run(tc.desc, func(t *testing.T) {
taskRun := parse.MustParseV1TaskRun(t, `
metadata:
name: test-imagepull-fail
namespace: foo
Expand All @@ -2392,54 +2363,73 @@ status:
- container: step-unnamed-1
name: unnamed-1
imageID: whatever
waiting:
message: Back-off pulling image "whatever"
reason: ImagePullBackOff
steps:
- container: step-unnamed-2
name: unnamed-2
running:
startedAt: "2022-06-09T10:13:41Z"
imageID: whatever
taskSpec:
sidecars:
- image: ubuntu
- image: whatever
steps:
- image: alpine
`)
expectedStatus := &apis.Condition{
Type: apis.ConditionSucceeded,
Status: corev1.ConditionFalse,
Reason: "TaskRunImagePullFailed",
Message: `The sidecar "unnamed-1" in TaskRun "test-imagepull-fail" failed to pull the image "whatever". The pod errored with the message: "Back-off pulling image "whatever"."`,
}
startTime, _ := time.Parse(time.RFC3339, "2022-06-09T10:13:41Z")
if tc.failure == "step" {
taskRun.Status.Steps[0].Waiting = &corev1.ContainerStateWaiting{
Message: tc.message,
Reason: tc.reason,
}
taskRun.Status.Sidecars[1].Running = &corev1.ContainerStateRunning{
StartedAt: metav1.NewTime(startTime),
}
stepNumber = 2
} else {
taskRun.Status.Sidecars[1].Waiting = &corev1.ContainerStateWaiting{
Message: tc.message,
Reason: tc.reason,
}
taskRun.Status.Steps[0].Running = &corev1.ContainerStateRunning{
StartedAt: metav1.NewTime(startTime),
}
stepNumber = 1
}

wantEvents := []string{
"Normal Started ",
`Warning Failed The sidecar "unnamed-1" in TaskRun "test-imagepull-fail" failed to pull the image "whatever". The pod errored with the message: "Back-off pulling image "whatever".`,
}
d := test.Data{
TaskRuns: []*v1.TaskRun{taskRun},
}
testAssets, cancel := getTaskRunController(t, d)
defer cancel()
c := testAssets.Controller
clients := testAssets.Clients
expectedStatus := &apis.Condition{
Type: apis.ConditionSucceeded,
Status: corev1.ConditionFalse,
Reason: "TaskRunImagePullFailed",
Message: fmt.Sprintf(`The %s "unnamed-%d" in TaskRun "test-imagepull-fail" failed to pull the image "whatever". The pod errored with the message: "%s."`, tc.failure, stepNumber, tc.message),
}

if err := c.Reconciler.Reconcile(testAssets.Ctx, getRunName(taskRun)); err != nil {
t.Fatalf("Unexpected error when reconciling completed TaskRun : %v", err)
}
newTr, err := clients.Pipeline.TektonV1().TaskRuns(taskRun.Namespace).Get(testAssets.Ctx, taskRun.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("Expected completed TaskRun %s to exist but instead got error when getting it: %v", taskRun.Name, err)
}
condition := newTr.Status.GetCondition(apis.ConditionSucceeded)
if d := cmp.Diff(expectedStatus, condition, ignoreLastTransitionTime); d != "" {
t.Fatalf("Did not get expected condition %s", diff.PrintWantGot(d))
}
err = k8sevent.CheckEventsOrdered(t, testAssets.Recorder.Events, taskRun.Name, wantEvents)
if err != nil {
t.Errorf(err.Error())
wantEvents := []string{
"Normal Started ",
fmt.Sprintf(`Warning Failed The %s "unnamed-%d" in TaskRun "test-imagepull-fail" failed to pull the image "whatever". The pod errored with the message: "%s.`, tc.failure, stepNumber, tc.message),
}
d := test.Data{
TaskRuns: []*v1.TaskRun{taskRun},
}
testAssets, cancel := getTaskRunController(t, d)
defer cancel()
c := testAssets.Controller
clients := testAssets.Clients

if err := c.Reconciler.Reconcile(testAssets.Ctx, getRunName(taskRun)); err != nil {
t.Fatalf("Unexpected error when reconciling completed TaskRun : %v", err)
}
newTr, err := clients.Pipeline.TektonV1().TaskRuns(taskRun.Namespace).Get(testAssets.Ctx, taskRun.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("Expected completed TaskRun %s to exist but instead got error when getting it: %v", taskRun.Name, err)
}
condition := newTr.Status.GetCondition(apis.ConditionSucceeded)
if d := cmp.Diff(expectedStatus, condition, ignoreLastTransitionTime); d != "" {
t.Fatalf("Did not get expected condition %s", diff.PrintWantGot(d))
}
err = k8sevent.CheckEventsOrdered(t, testAssets.Recorder.Events, taskRun.Name, wantEvents)
if err != nil {
t.Errorf(err.Error())
}
})
}
}

Expand Down
Loading