Skip to content

Commit

Permalink
feat(lifecycle-operator): introduce non-blocking deployment functiona…
Browse files Browse the repository at this point in the history
…lity for application lifecycle (#3113)

Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com>
  • Loading branch information
odubajDT committed Feb 26, 2024
1 parent c846e93 commit bf78974
Show file tree
Hide file tree
Showing 29 changed files with 496 additions and 101 deletions.
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
28 changes: 20 additions & 8 deletions lifecycle-operator/apis/lifecycle/v1beta1/keptnappversion_types.go
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

0 comments on commit bf78974

Please sign in to comment.