Skip to content

Commit

Permalink
fix(operator): cancel pending phases when evaluation fails (#408)
Browse files Browse the repository at this point in the history
Fixes #381
  • Loading branch information
odubajDT committed Nov 18, 2022
1 parent 9efa462 commit 7f15baf
Show file tree
Hide file tree
Showing 13 changed files with 882 additions and 14 deletions.
14 changes: 11 additions & 3 deletions operator/api/v1alpha1/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ const (
StateFailed KeptnState = "Failed"
StateUnknown KeptnState = "Unknown"
StatePending KeptnState = "Pending"
StateCancelled KeptnState = "Cancelled"
)

func (k KeptnState) IsCompleted() bool {
return k == StateSucceeded || k == StateFailed
return k == StateSucceeded || k == StateFailed || k == StateCancelled
}

func (k KeptnState) IsSucceeded() bool {
Expand All @@ -53,6 +54,10 @@ func (k KeptnState) IsFailed() bool {
return k == StateFailed
}

func (k KeptnState) IsCancelled() bool {
return k == StateCancelled
}

func (k KeptnState) IsPending() bool {
return k == StatePending
}
Expand All @@ -64,12 +69,15 @@ type StatusSummary struct {
succeeded int
pending int
unknown int
cancelled int
}

func UpdateStatusSummary(status KeptnState, summary StatusSummary) StatusSummary {
switch status {
case StateFailed:
summary.failed++
case StateCancelled:
summary.cancelled++
case StateSucceeded:
summary.succeeded++
case StateProgressing:
Expand All @@ -83,11 +91,11 @@ func UpdateStatusSummary(status KeptnState, summary StatusSummary) StatusSummary
}

func (s StatusSummary) GetTotalCount() int {
return s.failed + s.succeeded + s.progressing + s.pending + s.unknown
return s.failed + s.succeeded + s.progressing + s.pending + s.unknown + s.cancelled
}

func GetOverallState(s StatusSummary) KeptnState {
if s.failed > 0 {
if s.failed > 0 || s.cancelled > 0 {
return StateFailed
}
if s.progressing > 0 {
Expand Down
304 changes: 304 additions & 0 deletions operator/api/v1alpha1/common/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
package common

import (
"strings"
"testing"

"github.com/stretchr/testify/require"
)

func TestKeptnKeptnState_IsCompleted(t *testing.T) {
tests := []struct {
State KeptnState
Want bool
}{
{
State: StateProgressing,
Want: false,
},
{
State: StateFailed,
Want: true,
},
{
State: StateSucceeded,
Want: true,
},
{
State: StateCancelled,
Want: true,
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.Equal(t, tt.State.IsCompleted(), tt.Want)
})
}
}

func TestKeptnKeptnState_IsSucceeded(t *testing.T) {
tests := []struct {
State KeptnState
Want bool
}{
{
State: StateProgressing,
Want: false,
},
{
State: StateSucceeded,
Want: true,
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.Equal(t, tt.State.IsSucceeded(), tt.Want)
})
}
}

func TestKeptnKeptnState_IsFailed(t *testing.T) {
tests := []struct {
State KeptnState
Want bool
}{
{
State: StateSucceeded,
Want: false,
},
{
State: StateFailed,
Want: true,
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.Equal(t, tt.State.IsFailed(), tt.Want)
})
}
}

func TestKeptnKeptnState_IsCancelled(t *testing.T) {
tests := []struct {
State KeptnState
Want bool
}{
{
State: StateSucceeded,
Want: false,
},
{
State: StateCancelled,
Want: true,
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.Equal(t, tt.State.IsCancelled(), tt.Want)
})
}
}

func TestKeptnKeptnState_IsPending(t *testing.T) {
tests := []struct {
State KeptnState
Want bool
}{
{
State: StateSucceeded,
Want: false,
},
{
State: StatePending,
Want: true,
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.Equal(t, tt.State.IsPending(), tt.Want)
})
}
}

func Test_UpdateStatusSummary(t *testing.T) {
emmptySummary := StatusSummary{0, 0, 0, 0, 0, 0, 0}
tests := []struct {
State KeptnState
Want StatusSummary
}{
{
State: StateProgressing,
Want: StatusSummary{0, 1, 0, 0, 0, 0, 0},
},
{
State: StateFailed,
Want: StatusSummary{0, 0, 1, 0, 0, 0, 0},
},
{
State: StateSucceeded,
Want: StatusSummary{0, 0, 0, 1, 0, 0, 0},
},
{
State: StatePending,
Want: StatusSummary{0, 0, 0, 0, 1, 0, 0},
},
{
State: "",
Want: StatusSummary{0, 0, 0, 0, 1, 0, 0},
},
{
State: StateUnknown,
Want: StatusSummary{0, 0, 0, 0, 0, 1, 0},
},
{
State: StateCancelled,
Want: StatusSummary{0, 0, 0, 0, 0, 0, 1},
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.Equal(t, UpdateStatusSummary(tt.State, emmptySummary), tt.Want)
})
}
}

func Test_GetTotalCount(t *testing.T) {
summary := StatusSummary{2, 0, 2, 1, 0, 3, 5}
require.Equal(t, summary.GetTotalCount(), 11)
}

func Test_GeOverallState(t *testing.T) {
tests := []struct {
Name string
Summary StatusSummary
Want KeptnState
}{
{
Name: "failed",
Summary: StatusSummary{0, 0, 1, 0, 0, 0, 0},
Want: StateFailed,
},
{
Name: "cancelled",
Summary: StatusSummary{0, 0, 0, 0, 0, 0, 1},
Want: StateFailed,
},
{
Name: "progressing",
Summary: StatusSummary{0, 1, 0, 0, 0, 0, 0},
Want: StateProgressing,
},
{
Name: "pending",
Summary: StatusSummary{0, 0, 0, 0, 1, 0, 0},
Want: StatePending,
},
{
Name: "unknown",
Summary: StatusSummary{0, 0, 0, 0, 0, 1, 0},
Want: StateUnknown,
},
{
Name: "unknown totalcount",
Summary: StatusSummary{5, 0, 0, 0, 0, 1, 0},
Want: StateUnknown,
},
{
Name: "succeeded",
Summary: StatusSummary{1, 0, 0, 1, 0, 0, 0},
Want: StateSucceeded,
},
}
for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
require.Equal(t, GetOverallState(tt.Summary), tt.Want)
})
}
}

func Test_TruncateString(t *testing.T) {
tests := []struct {
Input string
Max int
Want string
}{
{
Input: "some_string",
Max: 20,
Want: "some_string",
},
{
Input: "some_string",
Max: 5,
Want: "some_",
},
{
Input: "",
Max: 5,
Want: "",
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.Equal(t, TruncateString(tt.Input, tt.Max), tt.Want)
})
}
}

func Test_GenerateTaskName(t *testing.T) {
tests := []struct {
Check CheckType
Name string
Want string
}{
{
Check: PreDeploymentCheckType,
Name: "short-name",
Want: "pre-short-name-",
},
{
Check: PreDeploymentCheckType,
Name: "",
Want: "pre--",
},
{
Check: PreDeploymentCheckType,
Name: "loooooooooooooooooooooooooooooooooooooong_name",
Want: "pre-looooooooooooooooooooooooooooooo-",
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.True(t, strings.HasPrefix(GenerateTaskName(tt.Check, tt.Name), tt.Want))
})
}
}

func Test_GenerateEvaluationName(t *testing.T) {
tests := []struct {
Check CheckType
Name string
Want string
}{
{
Check: PreDeploymentEvaluationCheckType,
Name: "short-name",
Want: "pre-eval-short-name-",
},
{
Check: PreDeploymentEvaluationCheckType,
Name: "",
Want: "pre-eval--",
},
{
Check: PreDeploymentEvaluationCheckType,
Name: "loooooooooooooooooooooooooooooooooooooong_name",
Want: "pre-eval-loooooooooooooooooooooooooo-",
},
}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
require.True(t, strings.HasPrefix(GenerateEvaluationName(tt.Check, tt.Name), tt.Want))
})
}
}
1 change: 1 addition & 0 deletions operator/api/v1alpha1/common/phases.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ var (
PhaseAppPostEvaluation = KeptnPhaseType{LongName: "App Post-Deployment Evaluations", ShortName: "AppPostDeployEvaluations"}
PhaseAppDeployment = KeptnPhaseType{LongName: "App Deployment", ShortName: "AppDeploy"}
PhaseCompleted = KeptnPhaseType{LongName: "Completed", ShortName: "Completed"}
PhaseCancelled = KeptnPhaseType{LongName: "Cancelled", ShortName: "Cancelled"}
)
16 changes: 16 additions & 0 deletions operator/api/v1alpha1/keptnappversion_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,3 +359,19 @@ func (a KeptnAppVersion) GetSpanKey(phase string) string {
func (v KeptnAppVersion) GetWorkloadNameOfApp(workloadName string) string {
return fmt.Sprintf("%s-%s", v.Spec.AppName, workloadName)
}

func (a *KeptnAppVersion) CancelRemainingPhases(phase common.KeptnPhaseType) {
// no need to cancel anything when post-eval tasks fail
if phase == common.PhaseAppPostEvaluation {
return
}
// cancel workload deployment and post-deployment tasks if app pre-eval failed
if phase == common.PhaseAppPreEvaluation {
a.Status.WorkloadOverallStatus = common.StateCancelled
}
// cancel post-deployment tasks if workload deployment failed
a.Status.PostDeploymentStatus = common.StateCancelled
a.Status.PostDeploymentEvaluationStatus = common.StateCancelled
a.Status.Status = common.StateFailed

}

0 comments on commit 7f15baf

Please sign in to comment.