Merge pull request #612 from fluxcd/granular-reasons
This commit is contained in:
commit
a4d6bbcdde
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -903,17 +903,20 @@ without completing. This can occur due to some of the following factors:
|
||||||
non-existing Secret.
|
non-existing Secret.
|
||||||
- The credentials in the referenced Secret are invalid.
|
- The credentials in the referenced Secret are invalid.
|
||||||
- The Bucket spec contains a generic misconfiguration.
|
- The Bucket spec contains a generic misconfiguration.
|
||||||
|
- A storage related failure when storing the artifact.
|
||||||
|
|
||||||
When this happens, the controller sets the `Ready` Condition status to `False`,
|
When this happens, the controller sets the `Ready` Condition status to `False`,
|
||||||
and adds a Condition with the following attributes to the Bucket's
|
and adds a Condition with the following attributes to the Bucket's
|
||||||
`.status.conditions`:
|
`.status.conditions`:
|
||||||
|
|
||||||
- `type: FetchFailed`
|
- `type: FetchFailed` | `type: StorageOperationFailed`
|
||||||
- `status: "True"`
|
- `status: "True"`
|
||||||
- `reason: AuthenticationFailed` | `reason: BucketOperationFailed`
|
- `reason: AuthenticationFailed` | `reason: BucketOperationFailed`
|
||||||
|
|
||||||
This condition has a ["negative polarity"][typical-status-properties],
|
This condition has a ["negative polarity"][typical-status-properties],
|
||||||
and is only present on the Bucket while the status value is `"True"`.
|
and is only present on the Bucket while the status value is `"True"`.
|
||||||
|
There may be more arbitrary values for the `reason` field to provide accurate
|
||||||
|
reason for a condition.
|
||||||
|
|
||||||
While the Bucket has this Condition, the controller will continue to attempt
|
While the Bucket has this Condition, the controller will continue to attempt
|
||||||
to produce an Artifact for the resource with an exponential backoff, until
|
to produce an Artifact for the resource with an exponential backoff, until
|
||||||
|
|
|
||||||
|
|
@ -763,17 +763,20 @@ factors:
|
||||||
- The verification of the Git commit signature failed.
|
- The verification of the Git commit signature failed.
|
||||||
- The credentials in the referenced Secret are invalid.
|
- The credentials in the referenced Secret are invalid.
|
||||||
- The GitRepository spec contains a generic misconfiguration.
|
- The GitRepository spec contains a generic misconfiguration.
|
||||||
|
- A storage related failure when storing the artifact.
|
||||||
|
|
||||||
When this happens, the controller sets the `Ready` Condition status to `False`,
|
When this happens, the controller sets the `Ready` Condition status to `False`,
|
||||||
and adds a Condition with the following attributes to the GitRepository's
|
and adds a Condition with the following attributes to the GitRepository's
|
||||||
`.status.conditions`:
|
`.status.conditions`:
|
||||||
|
|
||||||
- `type: FetchFailed` | `type: IncludeUnavailableCondition`
|
- `type: FetchFailed` | `type: IncludeUnavailable` | `type: StorageOperationFailed`
|
||||||
- `status: "True"`
|
- `status: "True"`
|
||||||
- `reason: AuthenticationFailed` | `reason: GitOperationFailed` | `reason: StorageOperationFailed`
|
- `reason: AuthenticationFailed` | `reason: GitOperationFailed`
|
||||||
|
|
||||||
This condition has a ["negative polarity"][typical-status-properties],
|
This condition has a ["negative polarity"][typical-status-properties],
|
||||||
and is only present on the GitRepository while the status value is `"True"`.
|
and is only present on the GitRepository while the status value is `"True"`.
|
||||||
|
There may be more arbitrary values for the `reason` field to provide accurate
|
||||||
|
reason for a condition.
|
||||||
|
|
||||||
In addition to the above Condition types, when the
|
In addition to the above Condition types, when the
|
||||||
[verification of a Git commit signature](#verification) fails. A condition with
|
[verification of a Git commit signature](#verification) fails. A condition with
|
||||||
|
|
|
||||||
|
|
@ -532,17 +532,20 @@ factors:
|
||||||
- The credentials in the [Source reference](#source-reference) Secret are
|
- The credentials in the [Source reference](#source-reference) Secret are
|
||||||
invalid.
|
invalid.
|
||||||
- The HelmChart spec contains a generic misconfiguration.
|
- The HelmChart spec contains a generic misconfiguration.
|
||||||
|
- A storage related failure when storing the artifact.
|
||||||
|
|
||||||
When this happens, the controller sets the `Ready` Condition status to `False`,
|
When this happens, the controller sets the `Ready` Condition status to `False`,
|
||||||
and adds a Condition with the following attributes to the HelmChart's
|
and adds a Condition with the following attributes to the HelmChart's
|
||||||
`.status.conditions`:
|
`.status.conditions`:
|
||||||
|
|
||||||
- `type: FetchFailed`
|
- `type: FetchFailed` | `type: StorageOperationFailed`
|
||||||
- `status: "True"`
|
- `status: "True"`
|
||||||
- `reason: AuthenticationFailed` | `reason: StorageOperationFailed` | `reason: URLInvalid` | `reason: IllegalPath` | `reason: Failed`
|
- `reason: AuthenticationFailed` | `reason: StorageOperationFailed` | `reason: URLInvalid` | `reason: IllegalPath` | `reason: Failed`
|
||||||
|
|
||||||
This condition has a ["negative polarity"][typical-status-properties],
|
This condition has a ["negative polarity"][typical-status-properties],
|
||||||
and is only present on the HelmChart while the status value is `"True"`.
|
and is only present on the HelmChart while the status value is `"True"`.
|
||||||
|
There may be more arbitrary values for the `reason` field to provide accurate
|
||||||
|
reason for a condition.
|
||||||
|
|
||||||
While the HelmChart has this Condition, the controller will continue to
|
While the HelmChart has this Condition, the controller will continue to
|
||||||
attempt to produce an Artifact for the resource with an exponential backoff,
|
attempt to produce an Artifact for the resource with an exponential backoff,
|
||||||
|
|
|
||||||
|
|
@ -475,17 +475,20 @@ factors:
|
||||||
non-existing Secret.
|
non-existing Secret.
|
||||||
- The credentials in the referenced Secret are invalid.
|
- The credentials in the referenced Secret are invalid.
|
||||||
- The HelmRepository spec contains a generic misconfiguration.
|
- The HelmRepository spec contains a generic misconfiguration.
|
||||||
|
- A storage related failure when storing the artifact.
|
||||||
|
|
||||||
When this happens, the controller sets the `Ready` Condition status to `False`,
|
When this happens, the controller sets the `Ready` Condition status to `False`,
|
||||||
and adds a Condition with the following attributes to the HelmRepository's
|
and adds a Condition with the following attributes to the HelmRepository's
|
||||||
`.status.conditions`:
|
`.status.conditions`:
|
||||||
|
|
||||||
- `type: FetchFailed`
|
- `type: FetchFailed` | `type: StorageOperationFailed`
|
||||||
- `status: "True"`
|
- `status: "True"`
|
||||||
- `reason: AuthenticationFailed` | `reason: IndexationFailed` | `reason: Failed`
|
- `reason: AuthenticationFailed` | `reason: IndexationFailed` | `reason: Failed`
|
||||||
|
|
||||||
This condition has a ["negative polarity"][typical-status-properties],
|
This condition has a ["negative polarity"][typical-status-properties],
|
||||||
and is only present on the HelmRepository while the status value is `"True"`.
|
and is only present on the HelmRepository while the status value is `"True"`.
|
||||||
|
There may be more arbitrary values for the `reason` field to provide accurate
|
||||||
|
reason for a condition.
|
||||||
|
|
||||||
While the HelmRepository has this Condition, the controller will continue to
|
While the HelmRepository has this Condition, the controller will continue to
|
||||||
attempt to produce an Artifact for the resource with an exponential backoff,
|
attempt to produce an Artifact for the resource with an exponential backoff,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue