@@ -22,11 +22,13 @@ import (
22
22
"errors"
23
23
"fmt"
24
24
"net/url"
25
+ "strings"
25
26
"time"
26
27
27
28
"github.com/docker/go-units"
28
29
"github.com/opencontainers/go-digest"
29
30
helmgetter "helm.sh/helm/v3/pkg/getter"
31
+ helmreg "helm.sh/helm/v3/pkg/registry"
30
32
corev1 "k8s.io/api/core/v1"
31
33
"k8s.io/apimachinery/pkg/runtime"
32
34
kuberecorder "k8s.io/client-go/tools/record"
@@ -139,8 +141,10 @@ func (r *HelmRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager,
139
141
WithEventFilter (
140
142
predicate .And (
141
143
predicate .Or (
144
+ // Allow default types or OCI types that require migration.
142
145
intpredicates.HelmRepositoryTypePredicate {RepositoryType : helmv1 .HelmRepositoryTypeDefault },
143
146
intpredicates.HelmRepositoryTypePredicate {RepositoryType : "" },
147
+ intpredicates.HelmRepositoryOCIMigrationPredicate {},
144
148
),
145
149
predicate .Or (predicate.GenerationChangedPredicate {}, predicates.ReconcileRequestedPredicate {}),
146
150
),
@@ -164,6 +168,36 @@ func (r *HelmRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reque
164
168
// Initialize the patch helper with the current version of the object.
165
169
serialPatcher := patch .NewSerialPatcher (obj , r .Client )
166
170
171
+ // HelmRepository OCI migration.
172
+ //
173
+ // If it's of type OCI, migrate the object.
174
+ if obj .Spec .Type == helmv1 .HelmRepositoryTypeOCI {
175
+ // Skip migration if suspended and not being deleted.
176
+ if obj .Spec .Suspend && obj .DeletionTimestamp .IsZero () {
177
+ return ctrl.Result {}, nil
178
+ }
179
+
180
+ if ! intpredicates .HelmRepositoryOCIRequireMigration (obj ) {
181
+ // Already migrated, nothing to do.
182
+ return ctrl.Result {}, nil
183
+ }
184
+
185
+ // Delete any artifact.
186
+ _ , err := r .reconcileDelete (ctx , obj )
187
+ if err != nil {
188
+ return ctrl.Result {}, err
189
+ }
190
+ // Delete finalizer and reset the status.
191
+ controllerutil .RemoveFinalizer (obj , sourcev1 .SourceFinalizer )
192
+ obj .Status = helmv1.HelmRepositoryStatus {}
193
+
194
+ if err := serialPatcher .Patch (ctx , obj ); err != nil {
195
+ return ctrl.Result {}, err
196
+ }
197
+
198
+ return ctrl.Result {}, nil
199
+ }
200
+
167
201
// recResult stores the abstracted reconcile result.
168
202
var recResult sreconcile.Result
169
203
@@ -193,8 +227,8 @@ func (r *HelmRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reque
193
227
r .Metrics .RecordDuration (ctx , obj , start )
194
228
}()
195
229
196
- // Examine if the object is under deletion or if a type change has happened .
197
- if ! obj .ObjectMeta .DeletionTimestamp .IsZero () || ( obj . Spec . Type != "" && obj . Spec . Type != helmv1 . HelmRepositoryTypeDefault ) {
230
+ // Examine if the object is under deletion.
231
+ if ! obj .ObjectMeta .DeletionTimestamp .IsZero () {
198
232
recResult , retErr = r .reconcileDelete (ctx , obj )
199
233
return
200
234
}
@@ -391,6 +425,18 @@ func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, sp *pat
391
425
// pointer is set to the newly fetched index.
392
426
func (r * HelmRepositoryReconciler ) reconcileSource (ctx context.Context , sp * patch.SerialPatcher ,
393
427
obj * helmv1.HelmRepository , artifact * sourcev1.Artifact , chartRepo * repository.ChartRepository ) (sreconcile.Result , error ) {
428
+ // Ensure it's not an OCI URL. API validation ensures that only
429
+ // http/https/oci scheme are allowed.
430
+ if strings .HasPrefix (obj .Spec .URL , helmreg .OCIScheme ) {
431
+ err := fmt .Errorf ("'oci' URL scheme cannot be used with 'default' HelmRepository type" )
432
+ e := serror .NewStalling (
433
+ fmt .Errorf ("invalid Helm repository URL: %w" , err ),
434
+ sourcev1 .URLInvalidReason ,
435
+ )
436
+ conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , err .Error ())
437
+ return sreconcile .ResultEmpty , e
438
+ }
439
+
394
440
normalizedURL , err := repository .NormalizeURL (obj .Spec .URL )
395
441
if err != nil {
396
442
e := serror .NewStalling (
0 commit comments