Skip to content

Commit d87018a

Browse files
committed
add replace condition helper
replaceCondition() replaces target condition with a replacement condition, retaining the transition time. This helps ensure that the last transition time of releases don't change when a release is marked from remediated to released. Signed-off-by: Sunny <darkowlzz@protonmail.com>
1 parent e627301 commit d87018a

File tree

2 files changed

+133
-4
lines changed

2 files changed

+133
-4
lines changed

internal/reconcile/atomic_release.go

+19-4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/fluxcd/pkg/runtime/logger"
3434
"github.com/fluxcd/pkg/runtime/patch"
3535
"github.com/fluxcd/pkg/ssa/jsondiff"
36+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3637

3738
v2 "github.com/fluxcd/helm-controller/api/v2beta2"
3839
"github.com/fluxcd/helm-controller/internal/action"
@@ -322,10 +323,9 @@ func (r *AtomicRelease) actionForState(ctx context.Context, req *Request, state
322323
// having the same chart version and values. As a result, we are already
323324
// in-sync without performing a release action.
324325
if conditions.IsTrue(req.Object, v2.RemediatedCondition) {
325-
conditions.Delete(req.Object, v2.RemediatedCondition)
326326
cur := req.Object.Status.History.Latest()
327327
msg := fmt.Sprintf(fmtUpgradeSuccess, cur.FullReleaseName(), cur.VersionedChartName())
328-
conditions.MarkTrue(req.Object, v2.ReleasedCondition, v2.UpgradeSucceededReason, msg)
328+
replaceCondition(req.Object, v2.RemediatedCondition, v2.ReleasedCondition, v2.UpgradeSucceededReason, msg, metav1.ConditionTrue)
329329
}
330330

331331
return nil, nil
@@ -401,10 +401,9 @@ func (r *AtomicRelease) actionForState(ctx context.Context, req *Request, state
401401
// a result, we are already in-sync without performing a release action,
402402
// the existing release needs to undergo testing.
403403
if conditions.IsTrue(req.Object, v2.RemediatedCondition) {
404-
conditions.Delete(req.Object, v2.RemediatedCondition)
405404
cur := req.Object.Status.History.Latest()
406405
msg := fmt.Sprintf(fmtUpgradeSuccess, cur.FullReleaseName(), cur.VersionedChartName())
407-
conditions.MarkTrue(req.Object, v2.ReleasedCondition, v2.UpgradeSucceededReason, msg)
406+
replaceCondition(req.Object, v2.RemediatedCondition, v2.ReleasedCondition, v2.UpgradeSucceededReason, msg, metav1.ConditionTrue)
408407
}
409408

410409
return NewTest(r.configFactory, r.eventRecorder), nil
@@ -520,3 +519,19 @@ func timeoutForAction(action ActionReconciler, obj *v2.HelmRelease) time.Duratio
520519
return obj.GetTimeout().Duration
521520
}
522521
}
522+
523+
// replaceCondition replaces existing target condition with replacement
524+
// condition, if present, for the given values, retaining the
525+
// LastTransitionTime.
526+
func replaceCondition(obj *v2.HelmRelease, target string, replacement string, reason string, msg string, status metav1.ConditionStatus) {
527+
c := conditions.Get(obj, target)
528+
if c != nil {
529+
conditions.Delete(obj, replacement)
530+
c.Status = status
531+
c.Type = replacement
532+
c.Reason = reason
533+
c.Message = msg
534+
conditions.Set(obj, c)
535+
conditions.Delete(obj, target)
536+
}
537+
}

internal/reconcile/atomic_release_test.go

+114
Original file line numberDiff line numberDiff line change
@@ -1557,3 +1557,117 @@ func TestAtomicRelease_actionForState(t *testing.T) {
15571557
})
15581558
}
15591559
}
1560+
1561+
func Test_replaceCondition(t *testing.T) {
1562+
g := NewWithT(t)
1563+
timestamp, err := time.Parse(time.UnixDate, "Wed Feb 25 11:06:39 GMT 2015")
1564+
g.Expect(err).ToNot(HaveOccurred())
1565+
1566+
tests := []struct {
1567+
name string
1568+
conditions []metav1.Condition
1569+
target string
1570+
replacement string
1571+
wantConditions []metav1.Condition
1572+
}{
1573+
{
1574+
name: "both conditions exist",
1575+
conditions: []metav1.Condition{
1576+
{
1577+
Type: v2.ReleasedCondition,
1578+
Status: metav1.ConditionFalse,
1579+
Reason: v2.UpgradeFailedReason,
1580+
Message: "upgrade failed",
1581+
ObservedGeneration: 1,
1582+
LastTransitionTime: metav1.NewTime(timestamp),
1583+
},
1584+
{
1585+
Type: v2.RemediatedCondition,
1586+
Status: metav1.ConditionTrue,
1587+
Reason: v2.RollbackSucceededReason,
1588+
Message: "rollback",
1589+
ObservedGeneration: 1,
1590+
LastTransitionTime: metav1.NewTime(timestamp),
1591+
},
1592+
},
1593+
target: v2.RemediatedCondition,
1594+
replacement: v2.ReleasedCondition,
1595+
wantConditions: []metav1.Condition{
1596+
{
1597+
Type: v2.ReleasedCondition,
1598+
Status: metav1.ConditionTrue,
1599+
Reason: v2.UpgradeSucceededReason,
1600+
Message: "foo",
1601+
ObservedGeneration: 1,
1602+
LastTransitionTime: metav1.NewTime(timestamp),
1603+
},
1604+
},
1605+
},
1606+
{
1607+
name: "no existing replacement condition",
1608+
conditions: []metav1.Condition{
1609+
{
1610+
Type: v2.RemediatedCondition,
1611+
Status: metav1.ConditionTrue,
1612+
Reason: v2.RollbackSucceededReason,
1613+
Message: "rollback",
1614+
ObservedGeneration: 1,
1615+
LastTransitionTime: metav1.NewTime(timestamp),
1616+
},
1617+
},
1618+
target: v2.RemediatedCondition,
1619+
replacement: v2.ReleasedCondition,
1620+
wantConditions: []metav1.Condition{
1621+
{
1622+
Type: v2.ReleasedCondition,
1623+
Status: metav1.ConditionTrue,
1624+
Reason: v2.UpgradeSucceededReason,
1625+
Message: "foo",
1626+
ObservedGeneration: 1,
1627+
LastTransitionTime: metav1.NewTime(timestamp),
1628+
},
1629+
},
1630+
},
1631+
{
1632+
name: "no existing target condition",
1633+
conditions: []metav1.Condition{
1634+
{
1635+
Type: v2.ReleasedCondition,
1636+
Status: metav1.ConditionFalse,
1637+
Reason: v2.UpgradeFailedReason,
1638+
Message: "upgrade failed",
1639+
ObservedGeneration: 1,
1640+
LastTransitionTime: metav1.NewTime(timestamp),
1641+
},
1642+
},
1643+
target: v2.RemediatedCondition,
1644+
replacement: v2.ReleasedCondition,
1645+
wantConditions: []metav1.Condition{
1646+
{
1647+
Type: v2.ReleasedCondition,
1648+
Status: metav1.ConditionFalse,
1649+
Reason: v2.UpgradeFailedReason,
1650+
Message: "upgrade failed",
1651+
ObservedGeneration: 1,
1652+
LastTransitionTime: metav1.NewTime(timestamp),
1653+
},
1654+
},
1655+
},
1656+
{
1657+
name: "no existing target and replacement conditions",
1658+
target: v2.RemediatedCondition,
1659+
replacement: v2.ReleasedCondition,
1660+
},
1661+
}
1662+
for _, tt := range tests {
1663+
t.Run(tt.name, func(t *testing.T) {
1664+
g := NewWithT(t)
1665+
1666+
obj := &v2.HelmRelease{}
1667+
obj.Generation = 1
1668+
obj.Status.Conditions = tt.conditions
1669+
replaceCondition(obj, tt.target, tt.replacement, v2.UpgradeSucceededReason, "foo", metav1.ConditionTrue)
1670+
g.Expect(obj.Status.Conditions).To(Equal(tt.wantConditions))
1671+
})
1672+
}
1673+
}

0 commit comments

Comments
 (0)