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

feat(lifecycle-operator): introduce non-blocking deployment functionality for application lifecycle #3113

Merged
merged 14 commits into from
Feb 26, 2024
Merged
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ integration-test:
chainsaw test --test-dir ./test/chainsaw/integration/
chainsaw test --test-dir ./test/chainsaw/testanalysis/
chainsaw test --test-dir ./test/chainsaw/testcertificate/
chainsaw test --test-dir ./test/chainsaw/non-blocking-deployment/

.PHONY: integration-test-local #these tests should run on a real cluster!
integration-test-local:
Expand All @@ -41,6 +42,7 @@ integration-test-local:
chainsaw test --test-dir ./test/chainsaw/testmetrics/ --config ./.chainsaw-local.yaml
chainsaw test --test-dir ./test/chainsaw/testanalysis/ --config ./.chainsaw-local.yaml
chainsaw test --test-dir ./test/chainsaw/testcertificate/ --config ./.chainsaw-local.yaml
chainsaw test --test-dir ./test/chainsaw/non-blocking-deployment/ --config ./.chainsaw-local.yaml

.PHONY: integration-test-scheduling-gates #these tests should run on a real cluster!
integration-test-scheduling-gates:
Expand Down
16 changes: 14 additions & 2 deletions lifecycle-operator/apis/lifecycle/v1beta1/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ const (
StateUnknown KeptnState = "Unknown"
StatePending KeptnState = "Pending"
StateDeprecated KeptnState = "Deprecated"
// Deprecated: Use StateDeprecated instead. Should only be used in checks for backwards compatibility reasons
StateWarning KeptnState = "Warning"
)

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

func (k KeptnState) IsSucceeded() bool {
Expand All @@ -78,6 +78,10 @@ func (k KeptnState) IsPending() bool {
return k == StatePending
}

func (k KeptnState) IsWarning() bool {
return k == StateWarning
}

type StatusSummary struct {
Total int
Progressing int
Expand Down Expand Up @@ -126,6 +130,14 @@ func GetOverallState(s StatusSummary) KeptnState {
return StateSucceeded
}

func GetOverallStateBlockedDeployment(s StatusSummary, blockedDeployment bool) KeptnState {
state := GetOverallState(s)
if !blockedDeployment && state == StateFailed {
return StateWarning
}
return state
}

func TruncateString(s string, max int) string {
if len(s) > max {
return s[:max]
Expand Down
64 changes: 64 additions & 0 deletions lifecycle-operator/apis/lifecycle/v1beta1/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ func TestKeptnState_IsCompleted(t *testing.T) {
}
}

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

func TestKeptnState_IsSucceeded(t *testing.T) {
tests := []struct {
State KeptnState
Expand Down Expand Up @@ -240,6 +265,45 @@ func Test_GeOverallState(t *testing.T) {
}
}

func Test_GeOverallStateBlockedDeployment(t *testing.T) {
tests := []struct {
Name string
Summary StatusSummary
Block bool
Want KeptnState
}{
{
Name: "failed blocking",
Summary: StatusSummary{0, 0, 1, 0, 0, 0, 0},
Block: true,
Want: StateFailed,
},
{
Name: "succeeded blocking",
Summary: StatusSummary{1, 0, 0, 1, 0, 0, 0},
Block: true,
Want: StateSucceeded,
},
{
Name: "failed non-blocking",
Summary: StatusSummary{0, 0, 1, 0, 0, 0, 0},
Block: false,
Want: StateWarning,
},
{
Name: "succeeded non-blocking",
Summary: StatusSummary{1, 0, 0, 1, 0, 0, 0},
Block: false,
Want: StateSucceeded,
},
}
for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
require.Equal(t, GetOverallStateBlockedDeployment(tt.Summary, tt.Block), tt.Want)
})
}
}

func Test_TruncateString(t *testing.T) {
tests := []struct {
Input string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,22 @@ func (a KeptnAppVersion) IsPreDeploymentEvaluationCompleted() bool {
return a.Status.PreDeploymentEvaluationStatus.IsCompleted()
}

func (a KeptnAppVersion) IsPreDeploymentSucceeded() bool {
return a.Status.PreDeploymentStatus.IsSucceeded()
func (a KeptnAppVersion) IsPreDeploymentSucceeded(isBlocking bool) bool {
if isBlocking {
return a.Status.PreDeploymentStatus.IsSucceeded()
}
return a.Status.PreDeploymentStatus.IsSucceeded() || a.Status.PreDeploymentStatus.IsWarning()
}

func (a KeptnAppVersion) IsPreDeploymentFailed() bool {
return a.Status.PreDeploymentStatus.IsFailed()
}

func (a KeptnAppVersion) IsPreDeploymentEvaluationSucceeded() bool {
return a.Status.PreDeploymentEvaluationStatus.IsSucceeded()
func (a KeptnAppVersion) IsPreDeploymentEvaluationSucceeded(isBlocking bool) bool {
if isBlocking {
return a.Status.PreDeploymentEvaluationStatus.IsSucceeded()
}
return a.Status.PreDeploymentEvaluationStatus.IsSucceeded() || a.Status.PreDeploymentEvaluationStatus.IsWarning()
}

func (a KeptnAppVersion) IsPreDeploymentEvaluationFailed() bool {
Expand All @@ -219,16 +225,22 @@ func (a KeptnAppVersion) IsPromotionFailed() bool {
return a.Status.PromotionStatus.IsFailed()
}

func (a KeptnAppVersion) IsPostDeploymentEvaluationSucceeded() bool {
return a.Status.PostDeploymentEvaluationStatus.IsSucceeded()
func (a KeptnAppVersion) IsPostDeploymentEvaluationSucceeded(isBlocking bool) bool {
if isBlocking {
return a.Status.PostDeploymentEvaluationStatus.IsSucceeded()
}
return a.Status.PostDeploymentEvaluationStatus.IsSucceeded() || a.Status.PostDeploymentEvaluationStatus.IsWarning()
}

func (a KeptnAppVersion) IsPostDeploymentEvaluationFailed() bool {
return a.Status.PostDeploymentEvaluationStatus.IsFailed()
}

func (a KeptnAppVersion) IsPostDeploymentSucceeded() bool {
return a.Status.PostDeploymentStatus.IsSucceeded()
func (a KeptnAppVersion) IsPostDeploymentSucceeded(isBlocking bool) bool {
if isBlocking {
return a.Status.PostDeploymentStatus.IsSucceeded()
}
return a.Status.PostDeploymentStatus.IsSucceeded() || a.Status.PostDeploymentStatus.IsWarning()
}

func (a KeptnAppVersion) IsPromotionSucceeded() bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ import (
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/propagation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestKeptnAppVersion(t *testing.T) {
app := &KeptnAppVersion{
ObjectMeta: metav1.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "app",
Namespace: "namespace",
},
Expand Down Expand Up @@ -83,19 +82,19 @@ func TestKeptnAppVersion(t *testing.T) {
}

require.True(t, app.IsPreDeploymentCompleted())
require.False(t, app.IsPreDeploymentSucceeded())
require.False(t, app.IsPreDeploymentSucceeded(true))
require.True(t, app.IsPreDeploymentFailed())

require.True(t, app.IsPreDeploymentEvaluationCompleted())
require.False(t, app.IsPreDeploymentEvaluationSucceeded())
require.False(t, app.IsPreDeploymentEvaluationSucceeded(true))
require.True(t, app.IsPreDeploymentEvaluationFailed())

require.True(t, app.IsPostDeploymentCompleted())
require.False(t, app.IsPostDeploymentSucceeded())
require.False(t, app.IsPostDeploymentSucceeded(true))
require.True(t, app.IsPostDeploymentFailed())

require.True(t, app.IsPostDeploymentEvaluationCompleted())
require.False(t, app.IsPostDeploymentEvaluationSucceeded())
require.False(t, app.IsPostDeploymentEvaluationSucceeded(true))
require.True(t, app.IsPostDeploymentEvaluationFailed())

require.True(t, app.IsPromotionCompleted())
Expand All @@ -106,6 +105,28 @@ func TestKeptnAppVersion(t *testing.T) {
require.False(t, app.AreWorkloadsSucceeded())
require.True(t, app.AreWorkloadsFailed())

app.Status.PreDeploymentStatus = common.StateWarning
app.Status.PreDeploymentEvaluationStatus = common.StateWarning
app.Status.PostDeploymentStatus = common.StateWarning
app.Status.PostDeploymentEvaluationStatus = common.StateWarning

require.False(t, app.IsPreDeploymentSucceeded(true))
require.True(t, app.IsPreDeploymentSucceeded(false))

require.False(t, app.IsPreDeploymentEvaluationSucceeded(true))
require.True(t, app.IsPreDeploymentEvaluationSucceeded(false))

require.False(t, app.IsPostDeploymentSucceeded(true))
require.True(t, app.IsPostDeploymentSucceeded(false))

require.False(t, app.IsPostDeploymentEvaluationSucceeded(true))
require.True(t, app.IsPostDeploymentEvaluationSucceeded(false))

app.Status.PreDeploymentStatus = common.StateFailed
app.Status.PreDeploymentEvaluationStatus = common.StateFailed
app.Status.PostDeploymentStatus = common.StateFailed
app.Status.PostDeploymentEvaluationStatus = common.StateFailed

require.False(t, app.IsEndTimeSet())
require.False(t, app.IsStartTimeSet())

Expand Down Expand Up @@ -257,7 +278,7 @@ func TestKeptnAppVersion(t *testing.T) {
AppName: app.GetParentName(),
EvaluationDefinition: "eval-def",
Type: common.PostDeploymentCheckType,
RetryInterval: metav1.Duration{
RetryInterval: v1.Duration{
Duration: 5 * time.Second,
},
}, evaluation.Spec)
Expand Down Expand Up @@ -503,15 +524,15 @@ func TestKeptnAppVersionList(t *testing.T) {
list := KeptnAppVersionList{
Items: []KeptnAppVersion{
{
ObjectMeta: metav1.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "obj1",
},
Status: KeptnAppVersionStatus{
Status: common.StateSucceeded,
},
},
{
ObjectMeta: metav1.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "obj2",
},
Status: KeptnAppVersionStatus{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import (
"github.com/keptn/lifecycle-toolkit/lifecycle-operator/apis/lifecycle/v1beta1/common"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestKeptnWorkload(t *testing.T) {
workload := &KeptnWorkload{
ObjectMeta: metav1.ObjectMeta{
ObjectMeta: v1.ObjectMeta{
Name: "workload",
Namespace: "namespace",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,22 @@ func (w KeptnWorkloadVersion) IsPreDeploymentEvaluationCompleted() bool {
return w.Status.PreDeploymentEvaluationStatus.IsCompleted()
}

func (w KeptnWorkloadVersion) IsPreDeploymentSucceeded() bool {
return w.Status.PreDeploymentStatus.IsSucceeded()
func (w KeptnWorkloadVersion) IsPreDeploymentSucceeded(isBlocking bool) bool {
if isBlocking {
return w.Status.PreDeploymentStatus.IsSucceeded()
}
return w.Status.PreDeploymentStatus.IsSucceeded() || w.Status.PreDeploymentStatus.IsWarning()
}

func (w KeptnWorkloadVersion) IsPreDeploymentFailed() bool {
return w.Status.PreDeploymentStatus.IsFailed()
}

func (w KeptnWorkloadVersion) IsPreDeploymentEvaluationSucceeded() bool {
return w.Status.PreDeploymentEvaluationStatus.IsSucceeded()
func (w KeptnWorkloadVersion) IsPreDeploymentEvaluationSucceeded(isBlocking bool) bool {
if isBlocking {
return w.Status.PreDeploymentEvaluationStatus.IsSucceeded()
}
return w.Status.PreDeploymentEvaluationStatus.IsSucceeded() || w.Status.PreDeploymentEvaluationStatus.IsWarning()
}

func (w KeptnWorkloadVersion) IsPreDeploymentEvaluationFailed() bool {
Expand All @@ -201,16 +207,22 @@ func (w KeptnWorkloadVersion) IsPostDeploymentEvaluationCompleted() bool {
return w.Status.PostDeploymentEvaluationStatus.IsCompleted()
}

func (w KeptnWorkloadVersion) IsPostDeploymentSucceeded() bool {
return w.Status.PostDeploymentStatus.IsSucceeded()
func (w KeptnWorkloadVersion) IsPostDeploymentSucceeded(isBlocking bool) bool {
if isBlocking {
return w.Status.PostDeploymentStatus.IsSucceeded()
}
return w.Status.PostDeploymentStatus.IsSucceeded() || w.Status.PostDeploymentStatus.IsWarning()
}

func (w KeptnWorkloadVersion) IsPostDeploymentFailed() bool {
return w.Status.PostDeploymentStatus.IsFailed()
}

func (w KeptnWorkloadVersion) IsPostDeploymentEvaluationSucceeded() bool {
return w.Status.PostDeploymentEvaluationStatus.IsSucceeded()
func (w KeptnWorkloadVersion) IsPostDeploymentEvaluationSucceeded(isBlocking bool) bool {
if isBlocking {
return w.Status.PostDeploymentEvaluationStatus.IsSucceeded()
}
return w.Status.PostDeploymentEvaluationStatus.IsSucceeded() || w.Status.PostDeploymentEvaluationStatus.IsWarning()
}

func (w KeptnWorkloadVersion) IsPostDeploymentEvaluationFailed() bool {
Expand Down
Loading
Loading