Add new condition StorageOperationFailedCondition

Introduce new condition StorageOperationFailedCondition for all the
failures related to the storage. It is a negative polarity condition and
is considered in computing summary of reconciliation.

Also, introduce more granular event reasons related to
StorageOperationFailedCondition for precise reasoning behind failures.
These replace the vague StorageOperationFailedReason.

Signed-off-by: Sunny <darkowlzz@protonmail.com>
This commit is contained in:
Sunny 2022-03-14 20:24:25 +05:30
parent 02c8fbae7f
commit a2d6af126d
No known key found for this signature in database
GPG Key ID: 9F3D25DDFF7FA3CF
7 changed files with 159 additions and 77 deletions

View File

@ -43,17 +43,41 @@ const (
// of a Source's Artifact. // of a Source's Artifact.
// If True, the Source can be in an ArtifactOutdatedCondition. // If True, the Source can be in an ArtifactOutdatedCondition.
BuildFailedCondition string = "BuildFailed" BuildFailedCondition string = "BuildFailed"
// StorageOperationFailedCondition indicates a transient or persistent
// failure related to storage. If True, the reconciliation failed while
// performing some filesystem operation.
StorageOperationFailedCondition string = "StorageOperationFailed"
) )
const ( const (
// URLInvalidReason signals that a given Source has an invalid URL. // URLInvalidReason signals that a given Source has an invalid URL.
URLInvalidReason string = "URLInvalid" URLInvalidReason string = "URLInvalid"
// StorageOperationFailedReason signals a failure caused by a storage
// operation.
StorageOperationFailedReason string = "StorageOperationFailed"
// AuthenticationFailedReason signals that a Secret does not have the // AuthenticationFailedReason signals that a Secret does not have the
// required fields, or the provided credentials do not match. // required fields, or the provided credentials do not match.
AuthenticationFailedReason string = "AuthenticationFailed" AuthenticationFailedReason string = "AuthenticationFailed"
// DirCreationFailedReason signals a failure caused by a directory creation
// operation.
DirCreationFailedReason string = "DirectoryCreationFailed"
// StatOperationFailedReason signals a failure caused by a stat operation on
// a path.
StatOperationFailedReason string = "StatOperationFailed"
// ReadOperationFailedReason signals a failure caused by a read operation.
ReadOperationFailedReason string = "ReadOperationFailed"
// AcquireLockFailedReason signals a failure in acquiring lock.
AcquireLockFailedReason string = "AcquireLockFailed"
// InvalidPathReason signals a failure caused by an invalid path.
InvalidPathReason string = "InvalidPath"
// ArchiveOperationFailedReason signals a failure in archive operation.
ArchiveOperationFailedReason string = "ArchiveOperationFailed"
// SymlinkUpdateFailedReason signals a failure in updating a symlink.
SymlinkUpdateFailedReason string = "SymlinkUpdateFailed"
) )

View File

@ -74,21 +74,24 @@ const maxConcurrentBucketFetches = 100
var bucketReadyCondition = summarize.Conditions{ var bucketReadyCondition = summarize.Conditions{
Target: meta.ReadyCondition, Target: meta.ReadyCondition,
Owned: []string{ Owned: []string{
sourcev1.ArtifactOutdatedCondition,
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.ReadyCondition, meta.ReadyCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
meta.StalledCondition, meta.StalledCondition,
}, },
Summarize: []string{ Summarize: []string{
sourcev1.ArtifactOutdatedCondition,
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.StalledCondition, meta.StalledCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
}, },
NegativePolarity: []string{ NegativePolarity: []string{
sourcev1.ArtifactOutdatedCondition,
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.StalledCondition, meta.StalledCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
}, },
@ -313,16 +316,19 @@ func (r *BucketReconciler) reconcile(ctx context.Context, obj *sourcev1.Bucket,
// Create temp working dir // Create temp working dir
tmpDir, err := os.MkdirTemp("", fmt.Sprintf("%s-%s-%s-", obj.Kind, obj.Namespace, obj.Name)) tmpDir, err := os.MkdirTemp("", fmt.Sprintf("%s-%s-%s-", obj.Kind, obj.Namespace, obj.Name))
if err != nil { if err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to create temporary directory: %w", err), Err: fmt.Errorf("failed to create temporary working directory: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.DirCreationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
defer func() { defer func() {
if err = os.RemoveAll(tmpDir); err != nil { if err = os.RemoveAll(tmpDir); err != nil {
ctrl.LoggerFrom(ctx).Error(err, "failed to remove temporary working directory") ctrl.LoggerFrom(ctx).Error(err, "failed to remove temporary working directory")
} }
}() }()
conditions.Delete(obj, sourcev1.StorageOperationFailedCondition)
// Run the sub-reconcilers and build the result of reconciliation. // Run the sub-reconcilers and build the result of reconciliation.
var ( var (
@ -521,23 +527,29 @@ func (r *BucketReconciler) reconcileArtifact(ctx context.Context, obj *sourcev1.
// Ensure target path exists and is a directory // Ensure target path exists and is a directory
if f, err := os.Stat(dir); err != nil { if f, err := os.Stat(dir); err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to stat source path: %w", err), Err: fmt.Errorf("failed to stat source path: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.StatOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} else if !f.IsDir() { } else if !f.IsDir() {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("source path '%s' is not a directory", dir), Err: fmt.Errorf("source path '%s' is not a directory", dir),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.InvalidPathReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
// Ensure artifact directory exists and acquire lock // Ensure artifact directory exists and acquire lock
if err := r.Storage.MkdirAll(artifact); err != nil { if err := r.Storage.MkdirAll(artifact); err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to create artifact directory: %w", err), Err: fmt.Errorf("failed to create artifact directory: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.DirCreationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
unlock, err := r.Storage.Lock(artifact) unlock, err := r.Storage.Lock(artifact)
if err != nil { if err != nil {
@ -550,10 +562,12 @@ func (r *BucketReconciler) reconcileArtifact(ctx context.Context, obj *sourcev1.
// Archive directory to storage // Archive directory to storage
if err := r.Storage.Archive(&artifact, dir, nil); err != nil { if err := r.Storage.Archive(&artifact, dir, nil); err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("unable to archive artifact to storage: %s", err), Err: fmt.Errorf("unable to archive artifact to storage: %s", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.ArchiveOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
r.annotatedEventLogf(ctx, obj, map[string]string{ r.annotatedEventLogf(ctx, obj, map[string]string{
"revision": artifact.Revision, "revision": artifact.Revision,
@ -566,12 +580,13 @@ func (r *BucketReconciler) reconcileArtifact(ctx context.Context, obj *sourcev1.
// Update symlink on a "best effort" basis // Update symlink on a "best effort" basis
url, err := r.Storage.Symlink(artifact, "latest.tar.gz") url, err := r.Storage.Symlink(artifact, "latest.tar.gz")
if err != nil { if err != nil {
r.eventLogf(ctx, obj, corev1.EventTypeWarning, sourcev1.StorageOperationFailedReason, r.eventLogf(ctx, obj, events.EventTypeTrace, sourcev1.SymlinkUpdateFailedReason,
"failed to update status URL symlink: %s", err) "failed to update status URL symlink: %s", err)
} }
if url != "" { if url != "" {
obj.Status.URL = url obj.Status.URL = url
} }
conditions.Delete(obj, sourcev1.StorageOperationFailedCondition)
return sreconcile.ResultSuccess, nil return sreconcile.ResultSuccess, nil
} }

View File

@ -947,6 +947,9 @@ func TestBucketReconciler_reconcileArtifact(t *testing.T) {
}, },
want: sreconcile.ResultEmpty, want: sreconcile.ResultEmpty,
wantErr: true, wantErr: true,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.StorageOperationFailedCondition, sourcev1.StatOperationFailedReason, "failed to stat source path"),
},
}, },
{ {
name: "Dir path is not a directory", name: "Dir path is not a directory",
@ -963,6 +966,9 @@ func TestBucketReconciler_reconcileArtifact(t *testing.T) {
}, },
want: sreconcile.ResultEmpty, want: sreconcile.ResultEmpty,
wantErr: true, wantErr: true,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.StorageOperationFailedCondition, sourcev1.InvalidPathReason, "is not a directory"),
},
}, },
} }

View File

@ -63,6 +63,7 @@ var gitRepositoryReadyCondition = summarize.Conditions{
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.IncludeUnavailableCondition, sourcev1.IncludeUnavailableCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.ReadyCondition, meta.ReadyCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
meta.StalledCondition, meta.StalledCondition,
@ -72,6 +73,7 @@ var gitRepositoryReadyCondition = summarize.Conditions{
sourcev1.SourceVerifiedCondition, sourcev1.SourceVerifiedCondition,
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.StalledCondition, meta.StalledCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
}, },
@ -79,6 +81,7 @@ var gitRepositoryReadyCondition = summarize.Conditions{
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.IncludeUnavailableCondition, sourcev1.IncludeUnavailableCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.StalledCondition, meta.StalledCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
}, },
@ -213,16 +216,19 @@ func (r *GitRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.G
// Create temp dir for Git clone // Create temp dir for Git clone
tmpDir, err := util.TempDirForObj("", obj) tmpDir, err := util.TempDirForObj("", obj)
if err != nil { if err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to create temporary directory: %w", err), Err: fmt.Errorf("failed to create temporary working directory: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.DirCreationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
defer func() { defer func() {
if err = os.RemoveAll(tmpDir); err != nil { if err = os.RemoveAll(tmpDir); err != nil {
ctrl.LoggerFrom(ctx).Error(err, "failed to remove temporary working directory") ctrl.LoggerFrom(ctx).Error(err, "failed to remove temporary working directory")
} }
}() }()
conditions.Delete(obj, sourcev1.StorageOperationFailedCondition)
// Run the sub-reconcilers and build the result of reconciliation. // Run the sub-reconcilers and build the result of reconciliation.
var ( var (
@ -322,7 +328,7 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
Err: fmt.Errorf("failed to get secret '%s': %w", name.String(), err), Err: fmt.Errorf("failed to get secret '%s': %w", name.String(), err),
Reason: sourcev1.AuthenticationFailedReason, Reason: sourcev1.AuthenticationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Return error as the world as observed may change // Return error as the world as observed may change
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -338,7 +344,7 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
Err: fmt.Errorf("failed to configure auth strategy for Git implementation '%s': %w", obj.Spec.GitImplementation, err), Err: fmt.Errorf("failed to configure auth strategy for Git implementation '%s': %w", obj.Spec.GitImplementation, err),
Reason: sourcev1.AuthenticationFailedReason, Reason: sourcev1.AuthenticationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Return error as the contents of the secret may change // Return error as the contents of the secret may change
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -358,7 +364,7 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
Err: fmt.Errorf("failed to configure checkout strategy for Git implementation '%s': %w", obj.Spec.GitImplementation, err), Err: fmt.Errorf("failed to configure checkout strategy for Git implementation '%s': %w", obj.Spec.GitImplementation, err),
Reason: sourcev1.GitOperationFailedReason, Reason: sourcev1.GitOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Do not return err as recovery without changes is impossible // Do not return err as recovery without changes is impossible
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -372,7 +378,7 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
Err: fmt.Errorf("failed to checkout and determine revision: %w", err), Err: fmt.Errorf("failed to checkout and determine revision: %w", err),
Reason: sourcev1.GitOperationFailedReason, Reason: sourcev1.GitOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Coin flip on transient or persistent error, return error and hope for the best // Coin flip on transient or persistent error, return error and hope for the best
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -429,15 +435,17 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
// Ensure target path exists and is a directory // Ensure target path exists and is a directory
if f, err := os.Stat(dir); err != nil { if f, err := os.Stat(dir); err != nil {
e := &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to stat target path: %w", err), Err: fmt.Errorf("failed to stat target artifact path: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.StatOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} else if !f.IsDir() { } else if !f.IsDir() {
e := &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("invalid target path: '%s' is not a directory", dir), Err: fmt.Errorf("invalid target path: '%s' is not a directory", dir),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.InvalidPathReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -445,8 +453,9 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
if err := r.Storage.MkdirAll(artifact); err != nil { if err := r.Storage.MkdirAll(artifact); err != nil {
e := &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to create artifact directory: %w", err), Err: fmt.Errorf("failed to create artifact directory: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.DirCreationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
unlock, err := r.Storage.Lock(artifact) unlock, err := r.Storage.Lock(artifact)
@ -472,10 +481,12 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
// Archive directory to storage // Archive directory to storage
if err := r.Storage.Archive(&artifact, dir, SourceIgnoreFilter(ps, nil)); err != nil { if err := r.Storage.Archive(&artifact, dir, SourceIgnoreFilter(ps, nil)); err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("unable to archive artifact to storage: %w", err), Err: fmt.Errorf("unable to archive artifact to storage: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.ArchiveOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
r.AnnotatedEventf(obj, map[string]string{ r.AnnotatedEventf(obj, map[string]string{
"revision": artifact.Revision, "revision": artifact.Revision,
@ -489,12 +500,13 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
// Update symlink on a "best effort" basis // Update symlink on a "best effort" basis
url, err := r.Storage.Symlink(artifact, "latest.tar.gz") url, err := r.Storage.Symlink(artifact, "latest.tar.gz")
if err != nil { if err != nil {
r.eventLogf(ctx, obj, corev1.EventTypeWarning, sourcev1.StorageOperationFailedReason, r.eventLogf(ctx, obj, events.EventTypeTrace, sourcev1.SymlinkUpdateFailedReason,
"failed to update status URL symlink: %s", err) "failed to update status URL symlink: %s", err)
} }
if url != "" { if url != "" {
obj.Status.URL = url obj.Status.URL = url
} }
conditions.Delete(obj, sourcev1.StorageOperationFailedCondition)
return sreconcile.ResultSuccess, nil return sreconcile.ResultSuccess, nil
} }
@ -520,7 +532,7 @@ func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context,
Err: fmt.Errorf("path calculation for include '%s' failed: %w", incl.GitRepositoryRef.Name, err), Err: fmt.Errorf("path calculation for include '%s' failed: %w", incl.GitRepositoryRef.Name, err),
Reason: "IllegalPath", Reason: "IllegalPath",
} }
conditions.MarkTrue(obj, sourcev1.IncludeUnavailableCondition, "IllegalPath", e.Err.Error()) conditions.MarkTrue(obj, sourcev1.IncludeUnavailableCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -531,7 +543,7 @@ func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context,
Err: fmt.Errorf("could not get resource for include '%s': %w", incl.GitRepositoryRef.Name, err), Err: fmt.Errorf("could not get resource for include '%s': %w", incl.GitRepositoryRef.Name, err),
Reason: "NotFound", Reason: "NotFound",
} }
conditions.MarkTrue(obj, sourcev1.IncludeUnavailableCondition, "NotFound", e.Err.Error()) conditions.MarkTrue(obj, sourcev1.IncludeUnavailableCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, err return sreconcile.ResultEmpty, err
} }
@ -541,7 +553,7 @@ func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context,
Err: fmt.Errorf("no artifact available for include '%s'", incl.GitRepositoryRef.Name), Err: fmt.Errorf("no artifact available for include '%s'", incl.GitRepositoryRef.Name),
Reason: "NoArtifact", Reason: "NoArtifact",
} }
conditions.MarkTrue(obj, sourcev1.IncludeUnavailableCondition, "NoArtifact", e.Err.Error()) conditions.MarkTrue(obj, sourcev1.IncludeUnavailableCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -551,7 +563,7 @@ func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context,
Err: fmt.Errorf("failed to copy '%s' include from %s to %s: %w", incl.GitRepositoryRef.Name, incl.GetFromPath(), incl.GetToPath(), err), Err: fmt.Errorf("failed to copy '%s' include from %s to %s: %w", incl.GitRepositoryRef.Name, incl.GetFromPath(), incl.GetToPath(), err),
Reason: "CopyFailure", Reason: "CopyFailure",
} }
conditions.MarkTrue(obj, sourcev1.IncludeUnavailableCondition, "CopyFailure", e.Err.Error()) conditions.MarkTrue(obj, sourcev1.IncludeUnavailableCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
artifacts[i] = dep.GetArtifact().DeepCopy() artifacts[i] = dep.GetArtifact().DeepCopy()
@ -598,7 +610,7 @@ func (r *GitRepositoryReconciler) verifyCommitSignature(ctx context.Context, obj
Err: fmt.Errorf("PGP public keys secret error: %w", err), Err: fmt.Errorf("PGP public keys secret error: %w", err),
Reason: "VerificationError", Reason: "VerificationError",
} }
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, meta.FailedReason, e.Err.Error()) conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -612,7 +624,7 @@ func (r *GitRepositoryReconciler) verifyCommitSignature(ctx context.Context, obj
Err: fmt.Errorf("signature verification of commit '%s' failed: %w", commit.Hash.String(), err), Err: fmt.Errorf("signature verification of commit '%s' failed: %w", commit.Hash.String(), err),
Reason: "InvalidCommitSignature", Reason: "InvalidCommitSignature",
} }
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, meta.FailedReason, e.Err.Error()) conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, e.Err.Error())
// Return error in the hope the secret changes // Return error in the hope the secret changes
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }

View File

@ -812,11 +812,17 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
name: "Target path does not exists", name: "Target path does not exists",
dir: "testdata/git/foo", dir: "testdata/git/foo",
wantErr: true, wantErr: true,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.StorageOperationFailedCondition, sourcev1.StatOperationFailedReason, "failed to stat target artifact path"),
},
}, },
{ {
name: "Target path is not a directory", name: "Target path is not a directory",
dir: "testdata/git/repository/foo.txt", dir: "testdata/git/repository/foo.txt",
wantErr: true, wantErr: true,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.StorageOperationFailedCondition, sourcev1.InvalidPathReason, "invalid target path"),
},
}, },
} }
artifactSize := func(g *WithT, artifactURL string) *int64 { artifactSize := func(g *WithT, artifactURL string) *int64 {
@ -1172,7 +1178,7 @@ func TestGitRepositoryReconciler_verifyCommitSignature(t *testing.T) {
}, },
wantErr: true, wantErr: true,
assertConditions: []metav1.Condition{ assertConditions: []metav1.Condition{
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, meta.FailedReason, "signature verification of commit 'shasum' failed: failed to verify commit with any of the given key rings"), *conditions.FalseCondition(sourcev1.SourceVerifiedCondition, "InvalidCommitSignature", "signature verification of commit 'shasum' failed: failed to verify commit with any of the given key rings"),
}, },
}, },
{ {
@ -1188,7 +1194,7 @@ func TestGitRepositoryReconciler_verifyCommitSignature(t *testing.T) {
}, },
wantErr: true, wantErr: true,
assertConditions: []metav1.Condition{ assertConditions: []metav1.Condition{
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, meta.FailedReason, "PGP public keys secret error: secrets \"none-existing\" not found"), *conditions.FalseCondition(sourcev1.SourceVerifiedCondition, "VerificationError", "PGP public keys secret error: secrets \"none-existing\" not found"),
}, },
}, },
{ {

View File

@ -72,6 +72,7 @@ var helmChartReadyCondition = summarize.Conditions{
sourcev1.BuildFailedCondition, sourcev1.BuildFailedCondition,
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.ReadyCondition, meta.ReadyCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
meta.StalledCondition, meta.StalledCondition,
@ -80,6 +81,7 @@ var helmChartReadyCondition = summarize.Conditions{
sourcev1.BuildFailedCondition, sourcev1.BuildFailedCondition,
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.StalledCondition, meta.StalledCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
}, },
@ -87,6 +89,7 @@ var helmChartReadyCondition = summarize.Conditions{
sourcev1.BuildFailedCondition, sourcev1.BuildFailedCondition,
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.StalledCondition, meta.StalledCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
}, },
@ -305,7 +308,7 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, obj *sourcev1
Err: fmt.Errorf("failed to get source: %w", err), Err: fmt.Errorf("failed to get source: %w", err),
Reason: "SourceUnavailable", Reason: "SourceUnavailable",
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, "SourceUnavailable", e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Return Kubernetes client errors, but ignore others which can only be // Return Kubernetes client errors, but ignore others which can only be
// solved by a change in generation // solved by a change in generation
@ -395,7 +398,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
Err: fmt.Errorf("failed to get secret '%s': %w", repo.Spec.SecretRef.Name, err), Err: fmt.Errorf("failed to get secret '%s': %w", repo.Spec.SecretRef.Name, err),
Reason: sourcev1.AuthenticationFailedReason, Reason: sourcev1.AuthenticationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Return error as the world as observed may change // Return error as the world as observed may change
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -407,7 +410,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
Err: fmt.Errorf("failed to configure Helm client with secret data: %w", err), Err: fmt.Errorf("failed to configure Helm client with secret data: %w", err),
Reason: sourcev1.AuthenticationFailedReason, Reason: sourcev1.AuthenticationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Requeue as content of secret might change // Requeue as content of secret might change
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -419,7 +422,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
Err: fmt.Errorf("failed to create TLS client config with secret data: %w", err), Err: fmt.Errorf("failed to create TLS client config with secret data: %w", err),
Reason: sourcev1.AuthenticationFailedReason, Reason: sourcev1.AuthenticationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Requeue as content of secret might change // Requeue as content of secret might change
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -436,14 +439,14 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
Err: fmt.Errorf("invalid Helm repository URL: %w", err), Err: fmt.Errorf("invalid Helm repository URL: %w", err),
Reason: sourcev1.URLInvalidReason, Reason: sourcev1.URLInvalidReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.URLInvalidReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
default: default:
e := &serror.Stalling{ e := &serror.Stalling{
Err: fmt.Errorf("failed to construct Helm client: %w", err), Err: fmt.Errorf("failed to construct Helm client: %w", err),
Reason: meta.FailedReason, Reason: meta.FailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, meta.FailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
} }
@ -486,9 +489,9 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj
if err != nil { if err != nil {
e := &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to create temporary working directory: %w", err), Err: fmt.Errorf("failed to create temporary working directory: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.DirCreationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.StorageOperationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
@ -498,9 +501,9 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj
if err := os.Mkdir(sourceDir, 0700); err != nil { if err := os.Mkdir(sourceDir, 0700); err != nil {
e := &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to create directory to untar source into: %w", err), Err: fmt.Errorf("failed to create directory to untar source into: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.DirCreationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.StorageOperationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -509,9 +512,9 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj
if err != nil { if err != nil {
e := &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to open source artifact: %w", err), Err: fmt.Errorf("failed to open source artifact: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.ReadOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.StorageOperationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
if _, err = untar.Untar(f, sourceDir); err != nil { if _, err = untar.Untar(f, sourceDir); err != nil {
@ -535,7 +538,7 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj
Err: fmt.Errorf("path calculation for chart '%s' failed: %w", obj.Spec.Chart, err), Err: fmt.Errorf("path calculation for chart '%s' failed: %w", obj.Spec.Chart, err),
Reason: "IllegalPath", Reason: "IllegalPath",
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, "IllegalPath", e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// We are unable to recover from this change without a change in generation // We are unable to recover from this change without a change in generation
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -639,26 +642,32 @@ func (r *HelmChartReconciler) reconcileArtifact(ctx context.Context, obj *source
// Ensure artifact directory exists and acquire lock // Ensure artifact directory exists and acquire lock
if err := r.Storage.MkdirAll(artifact); err != nil { if err := r.Storage.MkdirAll(artifact); err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to create artifact directory: %w", err), Err: fmt.Errorf("failed to create artifact directory: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.DirCreationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
unlock, err := r.Storage.Lock(artifact) unlock, err := r.Storage.Lock(artifact)
if err != nil { if err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to acquire lock for artifact: %w", err), Err: fmt.Errorf("failed to acquire lock for artifact: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.AcquireLockFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
defer unlock() defer unlock()
// Copy the packaged chart to the artifact path // Copy the packaged chart to the artifact path
if err = r.Storage.CopyFromPath(&artifact, b.Path); err != nil { if err = r.Storage.CopyFromPath(&artifact, b.Path); err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("unable to copy Helm chart to storage: %w", err), Err: fmt.Errorf("unable to copy Helm chart to storage: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.ArchiveOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
// Record it on the object // Record it on the object
@ -674,12 +683,13 @@ func (r *HelmChartReconciler) reconcileArtifact(ctx context.Context, obj *source
// Update symlink on a "best effort" basis // Update symlink on a "best effort" basis
symURL, err := r.Storage.Symlink(artifact, "latest.tar.gz") symURL, err := r.Storage.Symlink(artifact, "latest.tar.gz")
if err != nil { if err != nil {
r.eventLogf(ctx, obj, corev1.EventTypeWarning, sourcev1.StorageOperationFailedReason, r.eventLogf(ctx, obj, events.EventTypeTrace, sourcev1.SymlinkUpdateFailedReason,
"failed to update status URL symlink: %s", err) "failed to update status URL symlink: %s", err)
} }
if symURL != "" { if symURL != "" {
obj.Status.URL = symURL obj.Status.URL = symURL
} }
conditions.Delete(obj, sourcev1.StorageOperationFailedCondition)
return sreconcile.ResultSuccess, nil return sreconcile.ResultSuccess, nil
} }

View File

@ -59,6 +59,7 @@ var helmRepositoryReadyCondition = summarize.Conditions{
Owned: []string{ Owned: []string{
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.ReadyCondition, meta.ReadyCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
meta.StalledCondition, meta.StalledCondition,
@ -66,12 +67,14 @@ var helmRepositoryReadyCondition = summarize.Conditions{
Summarize: []string{ Summarize: []string{
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.StalledCondition, meta.StalledCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
}, },
NegativePolarity: []string{ NegativePolarity: []string{
sourcev1.FetchFailedCondition, sourcev1.FetchFailedCondition,
sourcev1.ArtifactOutdatedCondition, sourcev1.ArtifactOutdatedCondition,
sourcev1.StorageOperationFailedCondition,
meta.StalledCondition, meta.StalledCondition,
meta.ReconcilingCondition, meta.ReconcilingCondition,
}, },
@ -289,7 +292,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
Err: fmt.Errorf("failed to get secret '%s': %w", name.String(), err), Err: fmt.Errorf("failed to get secret '%s': %w", name.String(), err),
Reason: sourcev1.AuthenticationFailedReason, Reason: sourcev1.AuthenticationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -300,7 +303,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
Err: fmt.Errorf("failed to configure Helm client with secret data: %w", err), Err: fmt.Errorf("failed to configure Helm client with secret data: %w", err),
Reason: sourcev1.AuthenticationFailedReason, Reason: sourcev1.AuthenticationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Return err as the content of the secret may change. // Return err as the content of the secret may change.
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -312,7 +315,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
Err: fmt.Errorf("failed to create TLS client config with secret data: %w", err), Err: fmt.Errorf("failed to create TLS client config with secret data: %w", err),
Reason: sourcev1.AuthenticationFailedReason, Reason: sourcev1.AuthenticationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Requeue as content of secret might change // Requeue as content of secret might change
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -327,14 +330,14 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
Err: fmt.Errorf("invalid Helm repository URL: %w", err), Err: fmt.Errorf("invalid Helm repository URL: %w", err),
Reason: sourcev1.URLInvalidReason, Reason: sourcev1.URLInvalidReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.URLInvalidReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
default: default:
e := &serror.Stalling{ e := &serror.Stalling{
Err: fmt.Errorf("failed to construct Helm client: %w", err), Err: fmt.Errorf("failed to construct Helm client: %w", err),
Reason: meta.FailedReason, Reason: meta.FailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, meta.FailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
} }
@ -344,7 +347,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
Err: fmt.Errorf("failed to fetch Helm repository index: %w", err), Err: fmt.Errorf("failed to fetch Helm repository index: %w", err),
Reason: meta.FailedReason, Reason: meta.FailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, meta.FailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
// Coin flip on transient or persistent error, return error and hope for the best // Coin flip on transient or persistent error, return error and hope for the best
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
@ -354,9 +357,9 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
if err := chartRepo.LoadFromCache(); err != nil { if err := chartRepo.LoadFromCache(); err != nil {
e := &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to load Helm repository from cache: %w", err), Err: fmt.Errorf("failed to load Helm repository from cache: %w", err),
Reason: sourcev1.FetchFailedCondition, Reason: sourcev1.IndexationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.IndexationFailedReason, e.Err.Error()) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e return sreconcile.ResultEmpty, e
} }
defer chartRepo.Unload() defer chartRepo.Unload()
@ -409,10 +412,12 @@ func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, obj *s
// Create artifact dir // Create artifact dir
if err := r.Storage.MkdirAll(*artifact); err != nil { if err := r.Storage.MkdirAll(*artifact); err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("failed to create artifact directory: %w", err), Err: fmt.Errorf("failed to create artifact directory: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.DirCreationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
// Acquire lock. // Acquire lock.
@ -427,19 +432,23 @@ func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, obj *s
// Save artifact to storage. // Save artifact to storage.
if err = r.Storage.CopyFromPath(artifact, chartRepo.CachePath); err != nil { if err = r.Storage.CopyFromPath(artifact, chartRepo.CachePath); err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("unable to save artifact to storage: %w", err), Err: fmt.Errorf("unable to save artifact to storage: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.ArchiveOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
// Calculate the artifact size to be included in the NewArtifact event. // Calculate the artifact size to be included in the NewArtifact event.
fi, err := os.Stat(chartRepo.CachePath) fi, err := os.Stat(chartRepo.CachePath)
if err != nil { if err != nil {
return sreconcile.ResultEmpty, &serror.Event{ e := &serror.Event{
Err: fmt.Errorf("unable to read the artifact: %w", err), Err: fmt.Errorf("unable to read the artifact: %w", err),
Reason: sourcev1.StorageOperationFailedReason, Reason: sourcev1.ReadOperationFailedReason,
} }
conditions.MarkTrue(obj, sourcev1.StorageOperationFailedCondition, e.Reason, e.Err.Error())
return sreconcile.ResultEmpty, e
} }
size := units.HumanSize(float64(fi.Size())) size := units.HumanSize(float64(fi.Size()))
@ -454,13 +463,13 @@ func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, obj *s
// Update index symlink. // Update index symlink.
indexURL, err := r.Storage.Symlink(*artifact, "index.yaml") indexURL, err := r.Storage.Symlink(*artifact, "index.yaml")
if err != nil { if err != nil {
r.eventLogf(ctx, obj, corev1.EventTypeWarning, sourcev1.StorageOperationFailedReason, r.eventLogf(ctx, obj, events.EventTypeTrace, sourcev1.SymlinkUpdateFailedReason,
"failed to update status URL symlink: %s", err) "failed to update status URL symlink: %s", err)
} }
if indexURL != "" { if indexURL != "" {
obj.Status.URL = indexURL obj.Status.URL = indexURL
} }
conditions.Delete(obj, sourcev1.StorageOperationFailedCondition)
return sreconcile.ResultSuccess, nil return sreconcile.ResultSuccess, nil
} }