Take into account the oci-digest
This commit add the oci artifact digest into the release observed snapshot. This is used to later to add that value as an annotation. Signed-off-by: Soule BA <bah.soule@gmail.com>
This commit is contained in:
parent
49b47d4c44
commit
edec322a3d
|
|
@ -1002,11 +1002,16 @@ type HelmReleaseStatus struct {
|
||||||
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
|
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
|
||||||
|
|
||||||
// LastAttemptedRevision is the Source revision of the last reconciliation
|
// LastAttemptedRevision is the Source revision of the last reconciliation
|
||||||
// attempt. For OCIRegistry sources, the 12 first characters of the digest are
|
// attempt. For OCIRepository sources, the 12 first characters of the digest are
|
||||||
// appended to the chart version e.g. "1.2.3+1234567890ab".
|
// appended to the chart version e.g. "1.2.3+1234567890ab".
|
||||||
// +optional
|
// +optional
|
||||||
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
|
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
|
||||||
|
|
||||||
|
// LastAttemptedRevisionDigest is the digest of the last reconciliation attempt.
|
||||||
|
// This is only set for OCIRepository sources.
|
||||||
|
// +optional
|
||||||
|
LastAttemptedRevisionDigest string `json:"lastAttemptedRevisionDigest,omitempty"`
|
||||||
|
|
||||||
// LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last
|
// LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last
|
||||||
// reconciliation attempt.
|
// reconciliation attempt.
|
||||||
// Deprecated: Use LastAttemptedConfigDigest instead.
|
// Deprecated: Use LastAttemptedConfigDigest instead.
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,9 @@ type Snapshot struct {
|
||||||
// run by the controller.
|
// run by the controller.
|
||||||
// +optional
|
// +optional
|
||||||
TestHooks *map[string]*TestHookStatus `json:"testHooks,omitempty"`
|
TestHooks *map[string]*TestHookStatus `json:"testHooks,omitempty"`
|
||||||
|
// OCIDigest is the digest of the OCI artifact associated with the release.
|
||||||
|
// +optional
|
||||||
|
OCIDigest string `json:"ociDigest,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullReleaseName returns the full name of the release in the format
|
// FullReleaseName returns the full name of the release in the format
|
||||||
|
|
|
||||||
|
|
@ -1100,6 +1100,10 @@ spec:
|
||||||
description: Namespace is the namespace the release is deployed
|
description: Namespace is the namespace the release is deployed
|
||||||
to.
|
to.
|
||||||
type: string
|
type: string
|
||||||
|
ociDigest:
|
||||||
|
description: OCIDigest is the digest of the OCI artifact associated
|
||||||
|
with the release.
|
||||||
|
type: string
|
||||||
status:
|
status:
|
||||||
description: Status is the current state of the release.
|
description: Status is the current state of the release.
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -2374,6 +2378,10 @@ spec:
|
||||||
description: Namespace is the namespace the release is deployed
|
description: Namespace is the namespace the release is deployed
|
||||||
to.
|
to.
|
||||||
type: string
|
type: string
|
||||||
|
ociDigest:
|
||||||
|
description: OCIDigest is the digest of the OCI artifact associated
|
||||||
|
with the release.
|
||||||
|
type: string
|
||||||
status:
|
status:
|
||||||
description: Status is the current state of the release.
|
description: Status is the current state of the release.
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -2452,9 +2460,14 @@ spec:
|
||||||
lastAttemptedRevision:
|
lastAttemptedRevision:
|
||||||
description: |-
|
description: |-
|
||||||
LastAttemptedRevision is the Source revision of the last reconciliation
|
LastAttemptedRevision is the Source revision of the last reconciliation
|
||||||
attempt. For OCIRegistry sources, the 12 first characters of the digest are
|
attempt. For OCIRepository sources, the 12 first characters of the digest are
|
||||||
appended to the chart version e.g. "1.2.3+1234567890ab".
|
appended to the chart version e.g. "1.2.3+1234567890ab".
|
||||||
type: string
|
type: string
|
||||||
|
lastAttemptedRevisionDigest:
|
||||||
|
description: |-
|
||||||
|
LastAttemptedRevisionDigest is the digest of the last reconciliation attempt.
|
||||||
|
This is only set for OCIRepository sources.
|
||||||
|
type: string
|
||||||
lastAttemptedValuesChecksum:
|
lastAttemptedValuesChecksum:
|
||||||
description: |-
|
description: |-
|
||||||
LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last
|
LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last
|
||||||
|
|
|
||||||
|
|
@ -1584,12 +1584,25 @@ string
|
||||||
<td>
|
<td>
|
||||||
<em>(Optional)</em>
|
<em>(Optional)</em>
|
||||||
<p>LastAttemptedRevision is the Source revision of the last reconciliation
|
<p>LastAttemptedRevision is the Source revision of the last reconciliation
|
||||||
attempt. For OCIRegistry sources, the 12 first characters of the digest are
|
attempt. For OCIRepository sources, the 12 first characters of the digest are
|
||||||
appended to the chart version e.g. “1.2.3+1234567890ab”.</p>
|
appended to the chart version e.g. “1.2.3+1234567890ab”.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
<code>lastAttemptedRevisionDigest</code><br>
|
||||||
|
<em>
|
||||||
|
string
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>LastAttemptedRevisionDigest is the digest of the last reconciliation attempt.
|
||||||
|
This is only set for OCIRepository sources.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
<code>lastAttemptedValuesChecksum</code><br>
|
<code>lastAttemptedValuesChecksum</code><br>
|
||||||
<em>
|
<em>
|
||||||
string
|
string
|
||||||
|
|
@ -2380,6 +2393,18 @@ TestHookStatus
|
||||||
run by the controller.</p>
|
run by the controller.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>ociDigest</code><br>
|
||||||
|
<em>
|
||||||
|
string
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>OCIDigest is the digest of the OCI artifact associated with the release.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -242,26 +242,10 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
interval: 10m
|
interval: 10m
|
||||||
timeout: 5m
|
|
||||||
chartRef:
|
chartRef:
|
||||||
kind: OCIRepository
|
kind: OCIRepository
|
||||||
name: podinfo
|
name: podinfo
|
||||||
namespace: default
|
namespace: default
|
||||||
releaseName: podinfo
|
|
||||||
install:
|
|
||||||
remediation:
|
|
||||||
retries: 3
|
|
||||||
upgrade:
|
|
||||||
remediation:
|
|
||||||
retries: 3
|
|
||||||
test:
|
|
||||||
enable: true
|
|
||||||
driftDetection:
|
|
||||||
mode: enabled
|
|
||||||
ignore:
|
|
||||||
- paths: ["/spec/replicas"]
|
|
||||||
target:
|
|
||||||
kind: Deployment
|
|
||||||
values:
|
values:
|
||||||
replicaCount: 2
|
replicaCount: 2
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,11 @@ func VerifyReleaseObject(snapshot *v2.Snapshot, rls *helmrelease.Release) error
|
||||||
verifier := relDig.Verifier()
|
verifier := relDig.Verifier()
|
||||||
|
|
||||||
obs := release.ObserveRelease(rls)
|
obs := release.ObserveRelease(rls)
|
||||||
|
|
||||||
|
// unfortunately we have to pass in the OciDigest as is, because helmrelease.Release
|
||||||
|
// does not have a field for it.
|
||||||
|
obs.OCIDigest = snapshot.OCIDigest
|
||||||
|
|
||||||
if err = obs.Encode(verifier); err != nil {
|
if err = obs.Encode(verifier); err != nil {
|
||||||
// We are expected to be able to encode valid JSON, error out without a
|
// We are expected to be able to encode valid JSON, error out without a
|
||||||
// typed error assuming malfunction to signal to e.g. retry.
|
// typed error assuming malfunction to signal to e.g. retry.
|
||||||
|
|
|
||||||
|
|
@ -335,7 +335,7 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
|
||||||
conditions.MarkUnknown(obj, meta.ReadyCondition, meta.ProgressingReason, "reconciliation in progress")
|
conditions.MarkUnknown(obj, meta.ReadyCondition, meta.ProgressingReason, "reconciliation in progress")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mutateChartWithSourceRevision(loadedChart, source)
|
ociDigest, err := mutateChartWithSourceRevision(loadedChart, source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conditions.MarkFalse(obj, meta.ReadyCondition, "ChartMutateError", err.Error())
|
conditions.MarkFalse(obj, meta.ReadyCondition, "ChartMutateError", err.Error())
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
|
|
@ -388,6 +388,7 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
|
||||||
// Set last attempt values.
|
// Set last attempt values.
|
||||||
obj.Status.LastAttemptedGeneration = obj.Generation
|
obj.Status.LastAttemptedGeneration = obj.Generation
|
||||||
obj.Status.LastAttemptedRevision = loadedChart.Metadata.Version
|
obj.Status.LastAttemptedRevision = loadedChart.Metadata.Version
|
||||||
|
obj.Status.LastAttemptedRevisionDigest = ociDigest
|
||||||
obj.Status.LastAttemptedConfigDigest = chartutil.DigestValues(digest.Canonical, values).String()
|
obj.Status.LastAttemptedConfigDigest = chartutil.DigestValues(digest.Canonical, values).String()
|
||||||
obj.Status.LastAttemptedValuesChecksum = ""
|
obj.Status.LastAttemptedValuesChecksum = ""
|
||||||
obj.Status.LastReleaseRevision = 0
|
obj.Status.LastReleaseRevision = 0
|
||||||
|
|
@ -865,24 +866,28 @@ func getNamespacedName(obj *v2.HelmRelease) (types.NamespacedName, error) {
|
||||||
return namespacedName, nil
|
return namespacedName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mutateChartWithSourceRevision(chart *chart.Chart, source source.Source) error {
|
func mutateChartWithSourceRevision(chart *chart.Chart, source source.Source) (string, error) {
|
||||||
// If the source is an OCIRepository, we can try to mutate the chart version
|
// If the source is an OCIRepository, we can try to mutate the chart version
|
||||||
// with the artifact revision. The revision is either a <tag>@<digest> or
|
// with the artifact revision. The revision is either a <tag>@<digest> or
|
||||||
// just a digest.
|
// just a digest.
|
||||||
obj, ok := source.(*sourcev1.OCIRepository)
|
obj, ok := source.(*sourcev1.OCIRepository)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
// if not make sure to return an empty string to delete the digest of the
|
||||||
|
// last attempted revision
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
ver, err := semver.NewVersion(chart.Metadata.Version)
|
ver, err := semver.NewVersion(chart.Metadata.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ociDigest string
|
||||||
revision := obj.GetArtifact().Revision
|
revision := obj.GetArtifact().Revision
|
||||||
switch {
|
switch {
|
||||||
case strings.Contains(revision, "@"):
|
case strings.Contains(revision, "@"):
|
||||||
tagD := strings.Split(revision, "@")
|
tagD := strings.Split(revision, "@")
|
||||||
if len(tagD) != 2 || tagD[0] != chart.Metadata.Version {
|
if len(tagD) != 2 || tagD[0] != chart.Metadata.Version {
|
||||||
return fmt.Errorf("artifact revision %s does not match chart version %s", tagD[0], chart.Metadata.Version)
|
return "", fmt.Errorf("artifact revision %s does not match chart version %s", tagD[0], chart.Metadata.Version)
|
||||||
}
|
}
|
||||||
// algotithm are sha256, sha384, sha512 with the canonical being sha256
|
// algotithm are sha256, sha384, sha512 with the canonical being sha256
|
||||||
// So every digest starts with a sha algorithm and a colon
|
// So every digest starts with a sha algorithm and a colon
|
||||||
|
|
@ -890,17 +895,19 @@ func mutateChartWithSourceRevision(chart *chart.Chart, source source.Source) err
|
||||||
// add the digest to the chart version to make sure mutable tags are detected
|
// add the digest to the chart version to make sure mutable tags are detected
|
||||||
*ver, err = ver.SetMetadata(sha[0:12])
|
*ver, err = ver.SetMetadata(sha[0:12])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
ociDigest = tagD[1]
|
||||||
default:
|
default:
|
||||||
// default to the digest
|
// default to the digest
|
||||||
sha := strings.Split(revision, ":")[1]
|
sha := strings.Split(revision, ":")[1]
|
||||||
*ver, err = ver.SetMetadata(sha[0:12])
|
*ver, err = ver.SetMetadata(sha[0:12])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
ociDigest = revision
|
||||||
}
|
}
|
||||||
|
|
||||||
chart.Metadata.Version = ver.String()
|
chart.Metadata.Version = ver.String()
|
||||||
return nil
|
return ociDigest, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,10 @@ func TestHelmReleaseReconciler_reconcileRelease(t *testing.T) {
|
||||||
g := NewWithT(t)
|
g := NewWithT(t)
|
||||||
|
|
||||||
chart := &sourcev1b2.HelmChart{
|
chart := &sourcev1b2.HelmChart{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: sourcev1b2.GroupVersion.String(),
|
||||||
|
Kind: sourcev1b2.HelmChartKind,
|
||||||
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "chart",
|
Name: "chart",
|
||||||
Namespace: "mock",
|
Namespace: "mock",
|
||||||
|
|
@ -238,6 +242,10 @@ func TestHelmReleaseReconciler_reconcileRelease(t *testing.T) {
|
||||||
g := NewWithT(t)
|
g := NewWithT(t)
|
||||||
|
|
||||||
chart := &sourcev1b2.HelmChart{
|
chart := &sourcev1b2.HelmChart{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: sourcev1b2.GroupVersion.String(),
|
||||||
|
Kind: sourcev1b2.HelmChartKind,
|
||||||
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "chart",
|
Name: "chart",
|
||||||
Namespace: "mock",
|
Namespace: "mock",
|
||||||
|
|
@ -960,6 +968,10 @@ func TestHelmReleaseReconciler_reconcileReleaseFromOCIRepositorySource(t *testin
|
||||||
g := NewWithT(t)
|
g := NewWithT(t)
|
||||||
|
|
||||||
ocirepo := &sourcev1b2.OCIRepository{
|
ocirepo := &sourcev1b2.OCIRepository{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: sourcev1b2.GroupVersion.String(),
|
||||||
|
Kind: sourcev1b2.OCIRepositoryKind,
|
||||||
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "ocirepo",
|
Name: "ocirepo",
|
||||||
Namespace: "mock",
|
Namespace: "mock",
|
||||||
|
|
@ -2972,7 +2984,7 @@ func Test_TryMutateChartWithSourceRevision(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := mutateChartWithSourceRevision(c, s)
|
_, err := mutateChartWithSourceRevision(c, s)
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
g.Expect(err).To(HaveOccurred())
|
g.Expect(err).To(HaveOccurred())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,10 @@ func (r *CorrectClusterDrift) report(obj *v2.HelmRelease, changeSet *ssa.ChangeS
|
||||||
sb.WriteString(changeSet.String())
|
sb.WriteString(changeSet.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
r.eventRecorder.AnnotatedEventf(obj, eventMeta(cur.ChartVersion, cur.ConfigDigest), corev1.EventTypeWarning,
|
r.eventRecorder.AnnotatedEventf(obj, eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)), corev1.EventTypeWarning,
|
||||||
"DriftCorrectionFailed", sb.String())
|
"DriftCorrectionFailed", sb.String())
|
||||||
case changeSet != nil && len(changeSet.Entries) > 0:
|
case changeSet != nil && len(changeSet.Entries) > 0:
|
||||||
r.eventRecorder.AnnotatedEventf(obj, eventMeta(cur.ChartVersion, cur.ConfigDigest), corev1.EventTypeNormal,
|
r.eventRecorder.AnnotatedEventf(obj, eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)), corev1.EventTypeNormal,
|
||||||
"DriftCorrected", "Cluster state of release %s has been corrected:\n%s",
|
"DriftCorrected", "Cluster state of release %s has been corrected:\n%s",
|
||||||
obj.Status.History.Latest().FullReleaseName(), changeSet.String())
|
obj.Status.History.Latest().FullReleaseName(), changeSet.String())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ func (r *Install) Reconcile(ctx context.Context, req *Request) error {
|
||||||
_, err := action.Install(ctx, cfg, req.Object, req.Chart, req.Values)
|
_, err := action.Install(ctx, cfg, req.Object, req.Chart, req.Values)
|
||||||
|
|
||||||
// Record the history of releases observed during the install.
|
// Record the history of releases observed during the install.
|
||||||
obsReleases.recordOnObject(req.Object)
|
obsReleases.recordOnObject(req.Object, mutateOCIDigest)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.failure(req, logBuf, err)
|
r.failure(req, logBuf, err)
|
||||||
|
|
@ -154,7 +154,8 @@ func (r *Install) failure(req *Request, buffer *action.LogBuffer, err error) {
|
||||||
// Condition summary.
|
// Condition summary.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(req.Chart.Metadata.Version, chartutil.DigestValues(digest.Canonical, req.Values).String()),
|
eventMeta(req.Chart.Metadata.Version, chartutil.DigestValues(digest.Canonical, req.Values).String(),
|
||||||
|
addOCIDigest(req.Object.Status.LastAttemptedRevisionDigest)),
|
||||||
corev1.EventTypeWarning,
|
corev1.EventTypeWarning,
|
||||||
v2.InstallFailedReason,
|
v2.InstallFailedReason,
|
||||||
eventMessageWithLog(msg, buffer),
|
eventMessageWithLog(msg, buffer),
|
||||||
|
|
@ -181,7 +182,7 @@ func (r *Install) success(req *Request) {
|
||||||
// Record event.
|
// Record event.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeNormal,
|
corev1.EventTypeNormal,
|
||||||
v2.InstallSucceededReason,
|
v2.InstallSucceededReason,
|
||||||
msg,
|
msg,
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,9 @@ func TestInstall_failure(t *testing.T) {
|
||||||
ReleaseName: mockReleaseName,
|
ReleaseName: mockReleaseName,
|
||||||
TargetNamespace: mockReleaseNamespace,
|
TargetNamespace: mockReleaseNamespace,
|
||||||
},
|
},
|
||||||
|
Status: v2.HelmReleaseStatus{
|
||||||
|
LastAttemptedRevisionDigest: "sha256:1234567890",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
chrt = testutil.BuildChart()
|
chrt = testutil.BuildChart()
|
||||||
err = errors.New("installation error")
|
err = errors.New("installation error")
|
||||||
|
|
@ -337,6 +340,7 @@ func TestInstall_failure(t *testing.T) {
|
||||||
Message: expectMsg,
|
Message: expectMsg,
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
|
eventMetaGroupKey(metaOCIDigestKey): obj.Status.LastAttemptedRevisionDigest,
|
||||||
eventMetaGroupKey(eventv1.MetaRevisionKey): chrt.Metadata.Version,
|
eventMetaGroupKey(eventv1.MetaRevisionKey): chrt.Metadata.Version,
|
||||||
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, req.Values).String(),
|
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, req.Values).String(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ var (
|
||||||
ErrReleaseMismatch = errors.New("release mismatch")
|
ErrReleaseMismatch = errors.New("release mismatch")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// mutateObservedRelease is a function that mutates the Observation with the
|
||||||
|
// given HelmRelease object.
|
||||||
|
type mutateObservedRelease func(*v2.HelmRelease, release.Observation) release.Observation
|
||||||
|
|
||||||
// observedReleases is a map of Helm releases as observed to be written to the
|
// observedReleases is a map of Helm releases as observed to be written to the
|
||||||
// Helm storage. The key is the version of the release.
|
// Helm storage. The key is the version of the release.
|
||||||
type observedReleases map[int]release.Observation
|
type observedReleases map[int]release.Observation
|
||||||
|
|
@ -58,7 +62,7 @@ func (r observedReleases) sortedVersions() (versions []int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// recordOnObject records the observed releases on the HelmRelease object.
|
// recordOnObject records the observed releases on the HelmRelease object.
|
||||||
func (r observedReleases) recordOnObject(obj *v2.HelmRelease) {
|
func (r observedReleases) recordOnObject(obj *v2.HelmRelease, mutators ...mutateObservedRelease) {
|
||||||
switch len(r) {
|
switch len(r) {
|
||||||
case 0:
|
case 0:
|
||||||
return
|
return
|
||||||
|
|
@ -67,17 +71,25 @@ func (r observedReleases) recordOnObject(obj *v2.HelmRelease) {
|
||||||
for _, o := range r {
|
for _, o := range r {
|
||||||
obs = o
|
obs = o
|
||||||
}
|
}
|
||||||
|
for _, mut := range mutators {
|
||||||
|
obs = mut(obj, obs)
|
||||||
|
}
|
||||||
obj.Status.History = append(v2.Snapshots{release.ObservedToSnapshot(obs)}, obj.Status.History...)
|
obj.Status.History = append(v2.Snapshots{release.ObservedToSnapshot(obs)}, obj.Status.History...)
|
||||||
default:
|
default:
|
||||||
versions := r.sortedVersions()
|
versions := r.sortedVersions()
|
||||||
|
obs := r[versions[0]]
|
||||||
obj.Status.History = append(v2.Snapshots{release.ObservedToSnapshot(r[versions[0]])}, obj.Status.History...)
|
for _, mut := range mutators {
|
||||||
|
obs = mut(obj, obs)
|
||||||
|
}
|
||||||
|
obj.Status.History = append(v2.Snapshots{release.ObservedToSnapshot(obs)}, obj.Status.History...)
|
||||||
|
|
||||||
for _, ver := range versions[1:] {
|
for _, ver := range versions[1:] {
|
||||||
for i := range obj.Status.History {
|
for i := range obj.Status.History {
|
||||||
snap := obj.Status.History[i]
|
snap := obj.Status.History[i]
|
||||||
if snap.Targets(r[ver].Name, r[ver].Namespace, r[ver].Version) {
|
if snap.Targets(r[ver].Name, r[ver].Namespace, r[ver].Version) {
|
||||||
newSnap := release.ObservedToSnapshot(r[ver])
|
obs := r[ver]
|
||||||
|
obs.OCIDigest = snap.OCIDigest
|
||||||
|
newSnap := release.ObservedToSnapshot(obs)
|
||||||
newSnap.SetTestHooks(snap.GetTestHooks())
|
newSnap.SetTestHooks(snap.GetTestHooks())
|
||||||
obj.Status.History[i] = newSnap
|
obj.Status.History[i] = newSnap
|
||||||
return
|
return
|
||||||
|
|
@ -87,6 +99,11 @@ func (r observedReleases) recordOnObject(obj *v2.HelmRelease) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mutateOCIDigest(obj *v2.HelmRelease, obs release.Observation) release.Observation {
|
||||||
|
obs.OCIDigest = obj.Status.LastAttemptedRevisionDigest
|
||||||
|
return obs
|
||||||
|
}
|
||||||
|
|
||||||
// observeRelease returns a storage.ObserveFunc that stores the observed
|
// observeRelease returns a storage.ObserveFunc that stores the observed
|
||||||
// releases in the given observedReleases map.
|
// releases in the given observedReleases map.
|
||||||
// It can be used for Helm actions that modify multiple releases in the
|
// It can be used for Helm actions that modify multiple releases in the
|
||||||
|
|
@ -174,9 +191,15 @@ func eventMessageWithLog(msg string, log *action.LogBuffer) string {
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addMeta is a function that adds metadata to an event map.
|
||||||
|
type addMeta func(map[string]string)
|
||||||
|
|
||||||
|
// metaOCIDigestKey is the key for the OCI digest metadata.
|
||||||
|
const metaOCIDigestKey = "oci-digest"
|
||||||
|
|
||||||
// eventMeta returns the event (annotation) metadata based on the given
|
// eventMeta returns the event (annotation) metadata based on the given
|
||||||
// parameters.
|
// parameters.
|
||||||
func eventMeta(revision, token string) map[string]string {
|
func eventMeta(revision, token string, metas ...addMeta) map[string]string {
|
||||||
var metadata map[string]string
|
var metadata map[string]string
|
||||||
if revision != "" || token != "" {
|
if revision != "" || token != "" {
|
||||||
metadata = make(map[string]string)
|
metadata = make(map[string]string)
|
||||||
|
|
@ -187,9 +210,25 @@ func eventMeta(revision, token string) map[string]string {
|
||||||
metadata[eventMetaGroupKey(eventv1.MetaTokenKey)] = token
|
metadata[eventMetaGroupKey(eventv1.MetaTokenKey)] = token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, add := range metas {
|
||||||
|
add(metadata)
|
||||||
|
}
|
||||||
|
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addOCIDigest(digest string) addMeta {
|
||||||
|
return func(m map[string]string) {
|
||||||
|
if digest != "" {
|
||||||
|
if m == nil {
|
||||||
|
m = make(map[string]string)
|
||||||
|
}
|
||||||
|
m[eventMetaGroupKey(metaOCIDigestKey)] = digest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// eventMetaGroupKey returns the event (annotation) metadata key prefixed with
|
// eventMetaGroupKey returns the event (annotation) metadata key prefixed with
|
||||||
// the group.
|
// the group.
|
||||||
func eventMetaGroupKey(key string) string {
|
func eventMetaGroupKey(key string) string {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,12 @@ limitations under the License.
|
||||||
package reconcile
|
package reconcile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
"helm.sh/helm/v3/pkg/chart"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
@ -454,3 +456,179 @@ func mockLogBuffer(size int, lines int) *action.LogBuffer {
|
||||||
}
|
}
|
||||||
return log
|
return log
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_RecordOnObject(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
obj *v2.HelmRelease
|
||||||
|
r observedReleases
|
||||||
|
mutate bool
|
||||||
|
testFunc func(*v2.HelmRelease) error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "record observed releases",
|
||||||
|
obj: &v2.HelmRelease{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Namespace: mockReleaseNamespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
r: observedReleases{
|
||||||
|
1: {
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: 1,
|
||||||
|
ChartMetadata: chart.Metadata{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: "1.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
testFunc: func(obj *v2.HelmRelease) error {
|
||||||
|
if len(obj.Status.History) != 1 {
|
||||||
|
return fmt.Errorf("history length is not 1")
|
||||||
|
}
|
||||||
|
if obj.Status.History[0].Name != mockReleaseName {
|
||||||
|
return fmt.Errorf("release name is not %s", mockReleaseName)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "record observed releases with multiple versions",
|
||||||
|
obj: &v2.HelmRelease{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Namespace: mockReleaseNamespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
r: observedReleases{
|
||||||
|
1: {
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: 1,
|
||||||
|
ChartMetadata: chart.Metadata{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: "1.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: 2,
|
||||||
|
ChartMetadata: chart.Metadata{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: "2.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
testFunc: func(obj *v2.HelmRelease) error {
|
||||||
|
if len(obj.Status.History) != 1 {
|
||||||
|
return fmt.Errorf("want history length 1, got %d", len(obj.Status.History))
|
||||||
|
}
|
||||||
|
if obj.Status.History[0].Name != mockReleaseName {
|
||||||
|
return fmt.Errorf("release name is not %s", mockReleaseName)
|
||||||
|
}
|
||||||
|
if obj.Status.History[0].ChartVersion != "2.0.0" {
|
||||||
|
return fmt.Errorf("want chart version %s, got %s", "2.0.0", obj.Status.History[0].ChartVersion)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "record observed releases with status digest",
|
||||||
|
obj: &v2.HelmRelease{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Namespace: mockReleaseNamespace,
|
||||||
|
},
|
||||||
|
Status: v2.HelmReleaseStatus{
|
||||||
|
LastAttemptedRevisionDigest: "sha256:123456",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
r: observedReleases{
|
||||||
|
1: {
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: 1,
|
||||||
|
ChartMetadata: chart.Metadata{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: "1.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutate: true,
|
||||||
|
testFunc: func(obj *v2.HelmRelease) error {
|
||||||
|
h := obj.Status.History.Latest()
|
||||||
|
if h.Name != mockReleaseName {
|
||||||
|
return fmt.Errorf("release name is not %s", mockReleaseName)
|
||||||
|
}
|
||||||
|
if h.ChartVersion != "1.0.0" {
|
||||||
|
return fmt.Errorf("want chart version %s, got %s", "1.0.0", h.ChartVersion)
|
||||||
|
}
|
||||||
|
if h.OCIDigest != obj.Status.LastAttemptedRevisionDigest {
|
||||||
|
return fmt.Errorf("want digest %s, got %s", obj.Status.LastAttemptedRevisionDigest, h.OCIDigest)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "record observed releases with multiple versions and status digest",
|
||||||
|
obj: &v2.HelmRelease{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Namespace: mockReleaseNamespace,
|
||||||
|
},
|
||||||
|
Status: v2.HelmReleaseStatus{
|
||||||
|
LastAttemptedRevisionDigest: "sha256:123456",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
r: observedReleases{
|
||||||
|
1: {
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: 1,
|
||||||
|
ChartMetadata: chart.Metadata{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: "1.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: 2,
|
||||||
|
ChartMetadata: chart.Metadata{
|
||||||
|
Name: mockReleaseName,
|
||||||
|
Version: "2.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutate: true,
|
||||||
|
testFunc: func(obj *v2.HelmRelease) error {
|
||||||
|
if len(obj.Status.History) != 1 {
|
||||||
|
return fmt.Errorf("want history length 1, got %d", len(obj.Status.History))
|
||||||
|
}
|
||||||
|
h := obj.Status.History.Latest()
|
||||||
|
if h.Name != mockReleaseName {
|
||||||
|
return fmt.Errorf("release name is not %s", mockReleaseName)
|
||||||
|
}
|
||||||
|
if h.ChartVersion != "2.0.0" {
|
||||||
|
return fmt.Errorf("want chart version %s, got %s", "2.0.0", h.ChartVersion)
|
||||||
|
}
|
||||||
|
if h.OCIDigest != obj.Status.LastAttemptedRevisionDigest {
|
||||||
|
return fmt.Errorf("want digest %s, got %s", obj.Status.LastAttemptedRevisionDigest, h.OCIDigest)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
|
||||||
|
if tt.mutate {
|
||||||
|
tt.r.recordOnObject(tt.obj, mutateOCIDigest)
|
||||||
|
} else {
|
||||||
|
tt.r.recordOnObject(tt.obj)
|
||||||
|
}
|
||||||
|
err := tt.testFunc(tt.obj)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ func (r *RollbackRemediation) failure(req *Request, prev *v2.Snapshot, buffer *a
|
||||||
// Condition summary.
|
// Condition summary.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(prev.ChartVersion, chartutil.DigestValues(digest.Canonical, req.Values).String()),
|
eventMeta(prev.ChartVersion, chartutil.DigestValues(digest.Canonical, req.Values).String(), addOCIDigest(prev.OCIDigest)),
|
||||||
corev1.EventTypeWarning,
|
corev1.EventTypeWarning,
|
||||||
v2.RollbackFailedReason,
|
v2.RollbackFailedReason,
|
||||||
eventMessageWithLog(msg, buffer),
|
eventMessageWithLog(msg, buffer),
|
||||||
|
|
@ -162,7 +162,7 @@ func (r *RollbackRemediation) success(req *Request, prev *v2.Snapshot) {
|
||||||
// Record event.
|
// Record event.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(prev.ChartVersion, chartutil.DigestValues(digest.Canonical, req.Values).String()),
|
eventMeta(prev.ChartVersion, chartutil.DigestValues(digest.Canonical, req.Values).String(), addOCIDigest(prev.OCIDigest)),
|
||||||
corev1.EventTypeNormal,
|
corev1.EventTypeNormal,
|
||||||
v2.RollbackSucceededReason,
|
v2.RollbackSucceededReason,
|
||||||
msg,
|
msg,
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ func (r *Test) failure(req *Request, err error) {
|
||||||
// Condition summary.
|
// Condition summary.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeWarning,
|
corev1.EventTypeWarning,
|
||||||
v2.TestFailedReason,
|
v2.TestFailedReason,
|
||||||
msg,
|
msg,
|
||||||
|
|
@ -181,7 +181,7 @@ func (r *Test) success(req *Request) {
|
||||||
// Record event.
|
// Record event.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeNormal,
|
corev1.EventTypeNormal,
|
||||||
v2.TestSucceededReason,
|
v2.TestSucceededReason,
|
||||||
msg,
|
msg,
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ func (r *Uninstall) failure(req *Request, buffer *action.LogBuffer, err error) {
|
||||||
// Condition summary.
|
// Condition summary.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeWarning, v2.UninstallFailedReason,
|
corev1.EventTypeWarning, v2.UninstallFailedReason,
|
||||||
eventMessageWithLog(msg, buffer),
|
eventMessageWithLog(msg, buffer),
|
||||||
)
|
)
|
||||||
|
|
@ -201,7 +201,7 @@ func (r *Uninstall) success(req *Request) {
|
||||||
// Condition summary.
|
// Condition summary.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeNormal,
|
corev1.EventTypeNormal,
|
||||||
v2.UninstallSucceededReason,
|
v2.UninstallSucceededReason,
|
||||||
msg,
|
msg,
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ func (r *UninstallRemediation) failure(req *Request, buffer *action.LogBuffer, e
|
||||||
// Condition summary.
|
// Condition summary.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeWarning,
|
corev1.EventTypeWarning,
|
||||||
v2.UninstallFailedReason,
|
v2.UninstallFailedReason,
|
||||||
eventMessageWithLog(msg, buffer),
|
eventMessageWithLog(msg, buffer),
|
||||||
|
|
@ -175,7 +175,7 @@ func (r *UninstallRemediation) success(req *Request) {
|
||||||
// Record event.
|
// Record event.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeNormal,
|
corev1.EventTypeNormal,
|
||||||
v2.UninstallSucceededReason,
|
v2.UninstallSucceededReason,
|
||||||
msg,
|
msg,
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ func (r *Unlock) failure(req *Request, cur *v2.Snapshot, status helmrelease.Stat
|
||||||
// Record warning event.
|
// Record warning event.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeWarning,
|
corev1.EventTypeWarning,
|
||||||
"PendingRelease",
|
"PendingRelease",
|
||||||
msg,
|
msg,
|
||||||
|
|
@ -138,7 +138,7 @@ func (r *Unlock) success(req *Request, cur *v2.Snapshot, status helmrelease.Stat
|
||||||
// Record event.
|
// Record event.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeNormal,
|
corev1.EventTypeNormal,
|
||||||
"PendingRelease",
|
"PendingRelease",
|
||||||
msg,
|
msg,
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ func (r *Upgrade) Reconcile(ctx context.Context, req *Request) error {
|
||||||
_, err := action.Upgrade(ctx, cfg, req.Object, req.Chart, req.Values)
|
_, err := action.Upgrade(ctx, cfg, req.Object, req.Chart, req.Values)
|
||||||
|
|
||||||
// Record the history of releases observed during the upgrade.
|
// Record the history of releases observed during the upgrade.
|
||||||
obsReleases.recordOnObject(req.Object)
|
obsReleases.recordOnObject(req.Object, mutateOCIDigest)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.failure(req, logBuf, err)
|
r.failure(req, logBuf, err)
|
||||||
|
|
@ -144,7 +144,8 @@ func (r *Upgrade) failure(req *Request, buffer *action.LogBuffer, err error) {
|
||||||
// Condition summary.
|
// Condition summary.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(req.Chart.Metadata.Version, chartutil.DigestValues(digest.Canonical, req.Values).String()),
|
eventMeta(req.Chart.Metadata.Version, chartutil.DigestValues(digest.Canonical, req.Values).String(),
|
||||||
|
addOCIDigest(req.Object.Status.LastAttemptedRevisionDigest)),
|
||||||
corev1.EventTypeWarning,
|
corev1.EventTypeWarning,
|
||||||
v2.UpgradeFailedReason,
|
v2.UpgradeFailedReason,
|
||||||
eventMessageWithLog(msg, buffer),
|
eventMessageWithLog(msg, buffer),
|
||||||
|
|
@ -171,7 +172,7 @@ func (r *Upgrade) success(req *Request) {
|
||||||
// Record event.
|
// Record event.
|
||||||
r.eventRecorder.AnnotatedEventf(
|
r.eventRecorder.AnnotatedEventf(
|
||||||
req.Object,
|
req.Object,
|
||||||
eventMeta(cur.ChartVersion, cur.ConfigDigest),
|
eventMeta(cur.ChartVersion, cur.ConfigDigest, addOCIDigest(cur.OCIDigest)),
|
||||||
corev1.EventTypeNormal,
|
corev1.EventTypeNormal,
|
||||||
v2.UpgradeSucceededReason,
|
v2.UpgradeSucceededReason,
|
||||||
msg,
|
msg,
|
||||||
|
|
|
||||||
|
|
@ -438,6 +438,9 @@ func TestUpgrade_failure(t *testing.T) {
|
||||||
ReleaseName: mockReleaseName,
|
ReleaseName: mockReleaseName,
|
||||||
TargetNamespace: mockReleaseNamespace,
|
TargetNamespace: mockReleaseNamespace,
|
||||||
},
|
},
|
||||||
|
Status: v2.HelmReleaseStatus{
|
||||||
|
LastAttemptedRevisionDigest: "sha256:1234567890",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
chrt = testutil.BuildChart()
|
chrt = testutil.BuildChart()
|
||||||
err = errors.New("upgrade error")
|
err = errors.New("upgrade error")
|
||||||
|
|
@ -468,6 +471,7 @@ func TestUpgrade_failure(t *testing.T) {
|
||||||
Message: expectMsg,
|
Message: expectMsg,
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
|
eventMetaGroupKey(metaOCIDigestKey): obj.Status.LastAttemptedRevisionDigest,
|
||||||
eventMetaGroupKey(eventv1.MetaRevisionKey): chrt.Metadata.Version,
|
eventMetaGroupKey(eventv1.MetaRevisionKey): chrt.Metadata.Version,
|
||||||
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, req.Values).String(),
|
eventMetaGroupKey(eventv1.MetaTokenKey): chartutil.DigestValues(digest.Canonical, req.Values).String(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ func TestDigest(t *testing.T) {
|
||||||
rel: Observation{
|
rel: Observation{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
exp: "sha256:91b6773f7696d3eb405708a07e2daedc6e69664dabac8e10af7d570d09f947d5",
|
exp: "sha256:ca8901e499a79368647134cc4f1c2118f8e7ec64c8a4703b281d17fb01acfbed",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,8 @@ type Observation struct {
|
||||||
Hooks []helmrelease.Hook `json:"hooks"`
|
Hooks []helmrelease.Hook `json:"hooks"`
|
||||||
// Namespace is the Kubernetes namespace of the release.
|
// Namespace is the Kubernetes namespace of the release.
|
||||||
Namespace string `json:"namespace"`
|
Namespace string `json:"namespace"`
|
||||||
|
// OCIDigest is the digest of the OCI artifact that was used to
|
||||||
|
OCIDigest string `json:"ociDigest"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Targets returns if the release matches the given name, namespace and
|
// Targets returns if the release matches the given name, namespace and
|
||||||
|
|
@ -166,6 +168,7 @@ func ObservedToSnapshot(rls Observation) *v2.Snapshot {
|
||||||
LastDeployed: metav1.NewTime(rls.Info.LastDeployed.Time),
|
LastDeployed: metav1.NewTime(rls.Info.LastDeployed.Time),
|
||||||
Deleted: metav1.NewTime(rls.Info.Deleted.Time),
|
Deleted: metav1.NewTime(rls.Info.Deleted.Time),
|
||||||
Status: rls.Info.Status.String(),
|
Status: rls.Info.Status.String(),
|
||||||
|
OCIDigest: rls.OCIDigest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue