Skip to content

Commit

Permalink
feat: additional events when reconciliation starts
Browse files Browse the repository at this point in the history
Signed-off-by: Artem Miroshnychenko <[email protected]>
  • Loading branch information
artemlive committed Feb 8, 2024
1 parent 0114b20 commit 72f69e4
Show file tree
Hide file tree
Showing 15 changed files with 740 additions and 16 deletions.
20 changes: 20 additions & 0 deletions api/v2beta2/condition_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const (
)

const (
// InstallStartedReason represents the fact that the Helm install for the
// HelmRelease started.
InstallStartedReason string = "InstallStarted"

// InstallSucceededReason represents the fact that the Helm install for the
// HelmRelease succeeded.
InstallSucceededReason string = "InstallSucceeded"
Expand All @@ -40,6 +44,10 @@ const (
// HelmRelease failed.
InstallFailedReason string = "InstallFailed"

// UpgradeStartedReason represents the fact that the Helm upgrade for the
// HelmRelease started.
UpgradeStartedReason string = "UpgradeStarted"

// UpgradeSucceededReason represents the fact that the Helm upgrade for the
// HelmRelease succeeded.
UpgradeSucceededReason string = "UpgradeSucceeded"
Expand All @@ -48,6 +56,10 @@ const (
// HelmRelease failed.
UpgradeFailedReason string = "UpgradeFailed"

// TestStartedReason represents the fact that the Helm tests for the
// HelmRelease started.
TestStartedReason string = "TestStarted"

// TestSucceededReason represents the fact that the Helm tests for the
// HelmRelease succeeded.
TestSucceededReason string = "TestSucceeded"
Expand All @@ -56,6 +68,10 @@ const (
// failed.
TestFailedReason string = "TestFailed"

// RollbackStartedReason represents the fact that the Helm rollback for the
// HelmRelease started.
RollbackStartedReason string = "RollbackStarted"

// RollbackSucceededReason represents the fact that the Helm rollback for the
// HelmRelease succeeded.
RollbackSucceededReason string = "RollbackSucceeded"
Expand All @@ -64,6 +80,10 @@ const (
// HelmRelease failed.
RollbackFailedReason string = "RollbackFailed"

// UninstallStartedReason represents the fact that the Helm uninstall for the
// HelmRelease started.
UninstallStartedReason string = "UninstallStarted"

// UninstallSucceededReason represents the fact that the Helm uninstall for the
// HelmRelease succeeded.
UninstallSucceededReason string = "UninstallSucceeded"
Expand Down
14 changes: 14 additions & 0 deletions internal/reconcile/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
// cleared to mark the start of a new release lifecycle. This ensures we never
// attempt to roll back to a previous release before the install.
//
// When the installation starts, the object emits a corresponding event.
// During the installation process, the writes to the Helm storage are
// observed and recorded in the Status.History field of the Request.Object.
//
Expand Down Expand Up @@ -88,6 +89,17 @@ func (r *Install) Reconcile(ctx context.Context, req *Request) error {
conditions.Delete(req.Object, v2.TestSuccessCondition)
conditions.Delete(req.Object, v2.RemediatedCondition)

// Compose started message.
msg := fmt.Sprintf(fmtInstallStarted, req.Object.GetReleaseName(), req.Chart.Name())
// Record event.
r.eventRecorder.AnnotatedEventf(
req.Object,
eventMeta(req.Chart.Metadata.Version, chartutil.DigestValues(digest.Canonical, req.Values).String()),
corev1.EventTypeNormal,
v2.InstallStartedReason,
msg,
)

// Run the Helm install action.
_, err := action.Install(ctx, cfg, req.Object, req.Chart, req.Values)

Expand Down Expand Up @@ -126,6 +138,8 @@ func (r *Install) Type() ReconcilerType {
}

const (
// fmtInstallStarted is the message format for an installation start.
fmtInstallStarted = "Helm install started for release %s with chart %s"
// fmtInstallFailure is the message format for an installation failure.
fmtInstallFailure = "Helm install failed for release %s/%s with chart %s@%s: %s"
// fmtInstallSuccess is the message format for a successful installation.
Expand Down
102 changes: 100 additions & 2 deletions internal/reconcile/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
helmdriver "helm.sh/helm/v3/pkg/storage/driver"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/record"

eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
"github.com/fluxcd/pkg/apis/meta"
Expand Down Expand Up @@ -68,6 +67,9 @@ func TestInstall_Reconcile(t *testing.T) {
// expectedConditions are the conditions that are expected to be set on
// the HelmRelease after install.
expectConditions []metav1.Condition
// expectEvents is the expected Events of the HelmRelease
// after install.
expectEvents func(chart *chart.Chart) []corev1.Event
// expectHistory is the expected History of the HelmRelease after
// install.
expectHistory func(releases []*helmrelease.Release) v2.Snapshots
Expand All @@ -94,6 +96,21 @@ func TestInstall_Reconcile(t *testing.T) {
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
}
},
expectEvents: func(chart *chart.Chart) []corev1.Event {
return []corev1.Event{
{
Type: corev1.EventTypeNormal,
Reason: v2.InstallStartedReason,
Message: fmt.Sprintf(fmtInstallStarted, mockReleaseName, chart.Name()),
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
eventMetaGroupKey(eventv1.MetaRevisionKey): chart.Metadata.Version,
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, chart.Values).String(),
},
},
},
}
},
},
{
name: "install failure",
Expand All @@ -109,6 +126,21 @@ func TestInstall_Reconcile(t *testing.T) {
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
}
},
expectEvents: func(chart *chart.Chart) []corev1.Event {
return []corev1.Event{
{
Type: corev1.EventTypeNormal,
Reason: v2.InstallStartedReason,
Message: fmt.Sprintf(fmtInstallStarted, mockReleaseName, chart.Name()),
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
eventMetaGroupKey(eventv1.MetaRevisionKey): chart.Metadata.Version,
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, chart.Values).String(),
},
},
},
}
},
expectFailures: 1,
expectInstallFailures: 1,
},
Expand All @@ -128,6 +160,21 @@ func TestInstall_Reconcile(t *testing.T) {
*conditions.FalseCondition(v2.ReleasedCondition, v2.InstallFailedReason,
"storage create error"),
},
expectEvents: func(chart *chart.Chart) []corev1.Event {
return []corev1.Event{
{
Type: corev1.EventTypeNormal,
Reason: v2.InstallStartedReason,
Message: fmt.Sprintf(fmtInstallStarted, mockReleaseName, chart.Name()),
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
eventMetaGroupKey(eventv1.MetaRevisionKey): chart.Metadata.Version,
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, chart.Values).String(),
},
},
},
}
},
expectFailures: 1,
expectInstallFailures: 0,
},
Expand Down Expand Up @@ -163,6 +210,21 @@ func TestInstall_Reconcile(t *testing.T) {
*conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason,
"Helm install succeeded"),
},
expectEvents: func(chart *chart.Chart) []corev1.Event {
return []corev1.Event{
{
Type: corev1.EventTypeNormal,
Reason: v2.InstallStartedReason,
Message: fmt.Sprintf(fmtInstallStarted, mockReleaseName, chart.Name()),
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
eventMetaGroupKey(eventv1.MetaRevisionKey): chart.Metadata.Version,
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, chart.Values).String(),
},
},
},
}
},
expectHistory: func(releases []*helmrelease.Release) v2.Snapshots {
return v2.Snapshots{
release.ObservedToSnapshot(release.ObserveRelease(releases[1])),
Expand Down Expand Up @@ -191,6 +253,21 @@ func TestInstall_Reconcile(t *testing.T) {
*conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason,
"Helm install succeeded"),
},
expectEvents: func(chart *chart.Chart) []corev1.Event {
return []corev1.Event{
{
Type: corev1.EventTypeNormal,
Reason: v2.InstallStartedReason,
Message: fmt.Sprintf(fmtInstallStarted, mockReleaseName, chart.Name()),
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
eventMetaGroupKey(eventv1.MetaRevisionKey): chart.Metadata.Version,
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, chart.Values).String(),
},
},
},
}
},
expectHistory: func(releases []*helmrelease.Release) v2.Snapshots {
return v2.Snapshots{
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
Expand All @@ -214,6 +291,21 @@ func TestInstall_Reconcile(t *testing.T) {
*conditions.TrueCondition(v2.ReleasedCondition, v2.InstallSucceededReason,
"Helm install succeeded"),
},
expectEvents: func(chart *chart.Chart) []corev1.Event {
return []corev1.Event{
{
Type: corev1.EventTypeNormal,
Reason: v2.InstallStartedReason,
Message: fmt.Sprintf(fmtInstallStarted, mockReleaseName, chart.Name()),
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
eventMetaGroupKey(eventv1.MetaRevisionKey): chart.Metadata.Version,
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, chart.Values).String(),
},
},
},
}
},
expectHistory: func(releases []*helmrelease.Release) v2.Snapshots {
return v2.Snapshots{
release.ObservedToSnapshot(release.ObserveRelease(releases[0])),
Expand Down Expand Up @@ -270,7 +362,7 @@ func TestInstall_Reconcile(t *testing.T) {
cfg.Driver = tt.driver(cfg.Driver)
}

recorder := new(record.FakeRecorder)
recorder := testutil.NewFakeRecorder(10, false)
got := (NewInstall(cfg, recorder)).Reconcile(context.TODO(), &Request{
Object: obj,
Chart: tt.chart,
Expand All @@ -282,6 +374,12 @@ func TestInstall_Reconcile(t *testing.T) {
g.Expect(got).ToNot(HaveOccurred())
}

if tt.expectEvents != nil {
for _, event := range tt.expectEvents(tt.chart) {
g.Expect(recorder.GetEvents()).To(ContainElement(event))
}
}

g.Expect(obj.Status.Conditions).To(conditions.MatchConditions(tt.expectConditions))

releases, _ = store.History(mockReleaseName)
Expand Down
19 changes: 18 additions & 1 deletion internal/reconcile/rollback_remediation.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
// The writes to the Helm storage during the rollback are observed, and update
// the Status.History field.
//
// When rollback starts, the object emits a corresponding event.
// After a successful rollback, the object is marked with Remediated=True and
// an event is emitted. When the rollback fails, the object is marked with
// Remediated=False and a warning event is emitted.
Expand Down Expand Up @@ -94,8 +95,21 @@ func (r *RollbackRemediation) Reconcile(ctx context.Context, req *Request) error
ErrReleaseMismatch, prev.FullReleaseName(), cur.FullReleaseName())
}

// Compose started message.
msg := fmt.Sprintf(fmtRollbackRemediationStarted, prev.FullReleaseName(), prev.VersionedChartName())
// Record event.
r.eventRecorder.AnnotatedEventf(
req.Object,
eventMeta(cur.ChartVersion, chartutil.DigestValues(digest.Canonical, req.Values).String()),
corev1.EventTypeNormal,
v2.RollbackStartedReason,
msg,
)

// Run the Helm rollback action.
if err := action.Rollback(cfg, req.Object, prev.Name, action.RollbackToVersion(prev.Version)); err != nil {
err := action.Rollback(cfg, req.Object, prev.Name, action.RollbackToVersion(prev.Version))

if err != nil {
r.failure(req, prev, logBuf, err)

// Return error if we did not store a release, as this does not
Expand All @@ -120,6 +134,9 @@ func (r *RollbackRemediation) Type() ReconcilerType {
}

const (
// fmtRollbackRemediationStarted is the message format for a rollback
// remediation start.
fmtRollbackRemediationStarted = "Helm rollback to previous release %s with chart %s started"
// fmtRollbackRemediationFailure is the message format for a rollback
// remediation failure.
fmtRollbackRemediationFailure = "Helm rollback to previous release %s with chart %s failed: %s"
Expand Down
Loading

0 comments on commit 72f69e4

Please sign in to comment.