Skip to content

Commit

Permalink
Set limit on length of Status.Conditions of a csv
Browse files Browse the repository at this point in the history
Set a maximum length of Status.Conditions of ClusterServiceVersion
object(s). The oldest condition(s) should be removed from the list
as it grows over time to keep it at limit.

The default limit is set to 20.

Jira: https://jira.coreos.com/browse/OLM-963
  • Loading branch information
tkashem committed May 1, 2019
1 parent 48a1875 commit c4f83e1
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 15 deletions.
44 changes: 30 additions & 14 deletions pkg/api/apis/operators/v1alpha1/clusterserviceversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import (

const (
CopiedLabelKey = "olm.copiedFrom"

// ConditionsLengthLimit is the maximum length of Status.Conditions of a
// given ClusterServiceVersion object. The oldest condition(s) are removed
// from the list as it grows over time to keep it at limit.
ConditionsLengthLimit = 20
)

// obsoleteReasons are the set of reasons that mean a CSV should no longer be processed as active
Expand Down Expand Up @@ -67,6 +72,18 @@ func (c *ClusterServiceVersion) SetPhaseWithEvent(phase ClusterServiceVersionPha

// SetPhase sets the current phase and adds a condition if necessary
func (c *ClusterServiceVersion) SetPhase(phase ClusterServiceVersionPhase, reason ConditionReason, message string, now metav1.Time) {
newCondition := func() ClusterServiceVersionCondition {
return ClusterServiceVersionCondition{
Phase: c.Status.Phase,
LastTransitionTime: c.Status.LastTransitionTime,
LastUpdateTime: c.Status.LastUpdateTime,
Message: message,
Reason: reason,
}
}

defer c.TrimConditionsIfLimitExceeded()

c.Status.LastUpdateTime = now
if c.Status.Phase != phase {
c.Status.Phase = phase
Expand All @@ -75,23 +92,13 @@ func (c *ClusterServiceVersion) SetPhase(phase ClusterServiceVersionPhase, reaso
c.Status.Message = message
c.Status.Reason = reason
if len(c.Status.Conditions) == 0 {
c.Status.Conditions = append(c.Status.Conditions, ClusterServiceVersionCondition{
Phase: c.Status.Phase,
LastTransitionTime: c.Status.LastTransitionTime,
LastUpdateTime: c.Status.LastUpdateTime,
Message: message,
Reason: reason,
})
c.Status.Conditions = append(c.Status.Conditions, newCondition())
return
}

previousCondition := c.Status.Conditions[len(c.Status.Conditions)-1]
if previousCondition.Phase != c.Status.Phase || previousCondition.Reason != c.Status.Reason {
c.Status.Conditions = append(c.Status.Conditions, ClusterServiceVersionCondition{
Phase: c.Status.Phase,
LastTransitionTime: c.Status.LastTransitionTime,
LastUpdateTime: c.Status.LastUpdateTime,
Message: message,
Reason: reason,
})
c.Status.Conditions = append(c.Status.Conditions, newCondition())
}
}

Expand Down Expand Up @@ -190,3 +197,12 @@ func (set InstallModeSet) Supports(operatorNamespace string, namespaces []string

return nil
}

func (c *ClusterServiceVersion) TrimConditionsIfLimitExceeded() {
if len(c.Status.Conditions) <= ConditionsLengthLimit {
return
}

firstIndex := len(c.Status.Conditions) - ConditionsLengthLimit
c.Status.Conditions = c.Status.Conditions[firstIndex:len(c.Status.Conditions)]
}
112 changes: 111 additions & 1 deletion pkg/api/apis/operators/v1alpha1/clusterserviceversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"fmt"
"testing"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestSetRequirementStatus(t *testing.T) {
Expand Down Expand Up @@ -282,3 +284,111 @@ func TestSupports(t *testing.T) {
})
}
}

func TestSetPhaseWithConditionsLengthAtLimit(t *testing.T) {
csv := ClusterServiceVersion{}

limit := ConditionsLengthLimit
csv.Status.Conditions = helperNewConditions(limit)

now := metav1.Now()

// We expect the oldest condition to be removed.
oldConditionsWant := csv.Status.Conditions[1:]
lastAddedConditionWant := ClusterServiceVersionCondition{
Phase: ClusterServiceVersionPhase("Pending"),
LastTransitionTime: now,
LastUpdateTime: now,
Message: "message",
Reason: ConditionReason("reason"),
}

csv.SetPhase("Pending", "reason", "message", now)

conditionsGot := csv.Status.Conditions
assert.Equal(t, limit, len(conditionsGot))

oldConditionsGot := conditionsGot[0 : len(conditionsGot)-1]
assert.EqualValues(t, oldConditionsWant, oldConditionsGot)

lastAddedConditionGot := conditionsGot[len(conditionsGot)-1]
assert.Equal(t, lastAddedConditionWant, lastAddedConditionGot)
}

func TestSetPhaseWithConditionsLengthBelowLimit(t *testing.T) {
csv := ClusterServiceVersion{}

limit := ConditionsLengthLimit
csv.Status.Conditions = helperNewConditions(limit - 1)

now := metav1.Now()

// We expect no condition to be removed from the list.
oldConditionsWant := csv.Status.Conditions
lastAddedConditionWant := ClusterServiceVersionCondition{
Phase: ClusterServiceVersionPhase("Pending"),
LastTransitionTime: now,
LastUpdateTime: now,
Message: "message",
Reason: ConditionReason("reason"),
}

csv.SetPhase("Pending", "reason", "message", now)

conditionsGot := csv.Status.Conditions
assert.Equal(t, limit, len(conditionsGot))

oldConditionsGot := conditionsGot[0 : len(conditionsGot)-1]
assert.EqualValues(t, oldConditionsWant, oldConditionsGot)

lastAddedConditionGot := conditionsGot[len(conditionsGot)-1]
assert.Equal(t, lastAddedConditionWant, lastAddedConditionGot)
}

func TestSetPhaseWithLimitExceeded(t *testing.T) {
csv := ClusterServiceVersion{}

limit, extra := ConditionsLengthLimit, 10
csv.Status.Conditions = helperNewConditions(limit + extra)

now := metav1.Now()

// We expect extra plus 1 condition(s) to be removed from the list.
oldConditionsWant := csv.Status.Conditions[extra+1:]
lastAddedConditionWant := ClusterServiceVersionCondition{
Phase: ClusterServiceVersionPhase("Pending"),
LastTransitionTime: now,
LastUpdateTime: now,
Message: "message",
Reason: ConditionReason("reason"),
}

csv.SetPhase("Pending", "reason", "message", now)

conditionsGot := csv.Status.Conditions
assert.Equal(t, limit, len(conditionsGot))

oldConditionsGot := conditionsGot[0 : len(conditionsGot)-1]
assert.EqualValues(t, oldConditionsWant, oldConditionsGot)

lastAddedConditionGot := conditionsGot[len(conditionsGot)-1]
assert.Equal(t, lastAddedConditionWant, lastAddedConditionGot)
}

func helperNewConditions(count int) []ClusterServiceVersionCondition {
conditions := make([]ClusterServiceVersionCondition, 0)

for i := 1; i <= count; i++ {
now := metav1.Now()
condition := ClusterServiceVersionCondition{
Phase: ClusterServiceVersionPhase(fmt.Sprintf("phase-%d", i)),
LastTransitionTime: now,
LastUpdateTime: now,
Message: fmt.Sprintf("message-%d", i),
Reason: ConditionReason(fmt.Sprintf("reason-%d", i)),
}
conditions = append(conditions, condition)
}

return conditions
}

0 comments on commit c4f83e1

Please sign in to comment.