Skip to content

Commit cb86e4a

Browse files
committed
Implement ExternalArtifact reconciliation
Signed-off-by: Stefan Prodan <[email protected]>
1 parent d45da10 commit cb86e4a

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

internal/controller/helmrelease_controller.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,9 @@ func (r *HelmReleaseReconciler) getSource(ctx context.Context, obj *v2.HelmRelea
774774
if obj.Spec.ChartRef.Kind == sourcev1.OCIRepositoryKind {
775775
return r.getSourceFromOCIRef(ctx, obj)
776776
}
777+
if obj.Spec.ChartRef.Kind == sourcev1.ExternalArtifactKind {
778+
return r.getSourceFromExternalArtifact(ctx, obj)
779+
}
777780
name, namespace = obj.Spec.ChartRef.Name, obj.Spec.ChartRef.Namespace
778781
if namespace == "" {
779782
namespace = obj.GetNamespace()
@@ -813,6 +816,24 @@ func (r *HelmReleaseReconciler) getSourceFromOCIRef(ctx context.Context, obj *v2
813816
return &or, nil
814817
}
815818

819+
func (r *HelmReleaseReconciler) getSourceFromExternalArtifact(ctx context.Context, obj *v2.HelmRelease) (sourcev1.Source, error) {
820+
name, namespace := obj.Spec.ChartRef.Name, obj.Spec.ChartRef.Namespace
821+
if namespace == "" {
822+
namespace = obj.GetNamespace()
823+
}
824+
sourceRef := types.NamespacedName{Namespace: namespace, Name: name}
825+
826+
if err := intacl.AllowsAccessTo(obj, sourcev1.ExternalArtifactKind, sourceRef); err != nil {
827+
return nil, err
828+
}
829+
830+
or := sourcev1.ExternalArtifact{}
831+
if err := r.Client.Get(ctx, sourceRef, &or); err != nil {
832+
return nil, err
833+
}
834+
return &or, nil
835+
}
836+
816837
// waitForHistoryCacheSync returns a function that can be used to wait for the
817838
// cache backing the Kubernetes client to be in sync with the current state of
818839
// the v2.HelmRelease.
@@ -832,6 +853,13 @@ func (r *HelmReleaseReconciler) waitForHistoryCacheSync(obj *v2.HelmRelease) wai
832853
}
833854

834855
func isSourceReady(obj sourcev1.Source) (bool, string) {
856+
if o, ok := obj.(*sourcev1.ExternalArtifact); ok {
857+
if obj.GetArtifact() == nil {
858+
return false, fmt.Sprintf("ExternalArtifact '%s/%s' is not ready: does not have an artifact",
859+
o.GetNamespace(), o.GetName())
860+
}
861+
return true, ""
862+
}
835863
if o, ok := obj.(conditions.Getter); ok {
836864
return isReady(o, obj.GetArtifact())
837865
}

internal/controller/helmrelease_indexers.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,48 @@ func (r *HelmReleaseReconciler) requestsForOCIRepositoryChange(ctx context.Conte
105105
return reqs
106106
}
107107

108+
// requestsForExternalArtifactChange enqueues requests for watched ExternalArtifacts
109+
// according to the specified index.
110+
func (r *HelmReleaseReconciler) requestsForExternalArtifactChange(ctx context.Context, o client.Object) []reconcile.Request {
111+
or, ok := o.(*sourcev1.ExternalArtifact)
112+
if !ok {
113+
err := fmt.Errorf("expected an ExternalArtifact, got %T", o)
114+
ctrl.LoggerFrom(ctx).Error(err, "failed to get requests for ExternalArtifact change")
115+
return nil
116+
}
117+
// If we do not have an artifact, we have no requests to make
118+
if or.GetArtifact() == nil {
119+
return nil
120+
}
121+
122+
var list v2.HelmReleaseList
123+
if err := r.List(ctx, &list, client.MatchingFields{
124+
v2.SourceIndexKey: sourcev1.ExternalArtifactKind + "/" + client.ObjectKeyFromObject(or).String(),
125+
}); err != nil {
126+
ctrl.LoggerFrom(ctx).Error(err, "failed to list HelmReleases for ExternalArtifact change")
127+
return nil
128+
}
129+
130+
var reqs []reconcile.Request
131+
for i, hr := range list.Items {
132+
// If the HelmRelease is ready and the digest of the artifact equals to the
133+
// last attempted revision digest, we should not make a request for this HelmRelease,
134+
// likewise if we cannot retrieve the artifact digest.
135+
digest := extractDigest(or.GetArtifact().Revision)
136+
if digest == "" {
137+
ctrl.LoggerFrom(ctx).Error(fmt.Errorf("wrong digest for %T", or), "failed to get requests for ExternalArtifact change")
138+
continue
139+
}
140+
141+
if digest == hr.Status.LastAttemptedRevisionDigest {
142+
continue
143+
}
144+
145+
reqs = append(reqs, reconcile.Request{NamespacedName: client.ObjectKeyFromObject(&list.Items[i])})
146+
}
147+
return reqs
148+
}
149+
108150
// requestsForConfigDependency enqueues requests for watched ConfigMaps or Secrets
109151
// according to the specified index.
110152
func (r *HelmReleaseReconciler) requestsForConfigDependency(

internal/controller/helmrelease_manager.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ func (r *HelmReleaseReconciler) SetupWithManager(ctx context.Context, mgr ctrl.M
133133
handler.EnqueueRequestsFromMapFunc(r.requestsForOCIRepositoryChange),
134134
builder.WithPredicates(intpredicates.SourceRevisionChangePredicate{}),
135135
).
136+
Watches(
137+
&sourcev1.ExternalArtifact{},
138+
handler.EnqueueRequestsFromMapFunc(r.requestsForExternalArtifactChange),
139+
builder.WithPredicates(intpredicates.SourceRevisionChangePredicate{}),
140+
).
136141
WatchesMetadata(
137142
&corev1.ConfigMap{},
138143
handler.EnqueueRequestsFromMapFunc(r.requestsForConfigDependency(indexConfigMap)),

0 commit comments

Comments
 (0)