@@ -21,21 +21,20 @@ import (
21
21
"crypto/tls"
22
22
"errors"
23
23
"fmt"
24
- "github.com/fluxcd/pkg/git"
25
- "github.com/opencontainers/go-digest"
24
+
26
25
"net/url"
27
26
"os"
28
27
"path/filepath"
29
28
"strconv"
30
29
"strings"
31
30
"time"
32
31
33
- eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
34
- soci "github.com/fluxcd/source-controller/internal/oci"
35
32
"github.com/google/go-containerregistry/pkg/authn"
36
33
"github.com/google/go-containerregistry/pkg/v1/remote"
34
+ "github.com/opencontainers/go-digest"
37
35
helmgetter "helm.sh/helm/v3/pkg/getter"
38
36
helmreg "helm.sh/helm/v3/pkg/registry"
37
+ helmrepo "helm.sh/helm/v3/pkg/repo"
39
38
corev1 "k8s.io/api/core/v1"
40
39
apierrs "k8s.io/apimachinery/pkg/api/errors"
41
40
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -54,7 +53,9 @@ import (
54
53
"sigs.k8s.io/controller-runtime/pkg/reconcile"
55
54
"sigs.k8s.io/controller-runtime/pkg/source"
56
55
56
+ eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
57
57
"github.com/fluxcd/pkg/apis/meta"
58
+ "github.com/fluxcd/pkg/git"
58
59
"github.com/fluxcd/pkg/oci"
59
60
"github.com/fluxcd/pkg/runtime/conditions"
60
61
helper "github.com/fluxcd/pkg/runtime/controller"
@@ -70,6 +71,7 @@ import (
70
71
"github.com/fluxcd/source-controller/internal/helm/getter"
71
72
"github.com/fluxcd/source-controller/internal/helm/registry"
72
73
"github.com/fluxcd/source-controller/internal/helm/repository"
74
+ soci "github.com/fluxcd/source-controller/internal/oci"
73
75
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
74
76
"github.com/fluxcd/source-controller/internal/reconcile/summarize"
75
77
"github.com/fluxcd/source-controller/internal/util"
@@ -527,7 +529,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
527
529
}
528
530
529
531
// Build client options from secret
530
- opts , tls , err := r .clientOptionsFromSecret (secret , normalizedURL )
532
+ opts , tlsCfg , err := r .clientOptionsFromSecret (secret , normalizedURL )
531
533
if err != nil {
532
534
e := & serror.Event {
533
535
Err : err ,
@@ -538,7 +540,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
538
540
return sreconcile .ResultEmpty , e
539
541
}
540
542
clientOpts = append (clientOpts , opts ... )
541
- tlsConfig = tls
543
+ tlsConfig = tlsCfg
542
544
543
545
// Build registryClient options from secret
544
546
keychain , err = registry .LoginOptionFromSecret (normalizedURL , * secret )
@@ -651,34 +653,26 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
651
653
}
652
654
}
653
655
default :
654
- httpChartRepo , err := repository .NewChartRepository (normalizedURL , r .Storage .LocalPath (* repo .GetArtifact ()), r .Getters , tlsConfig , clientOpts ,
655
- repository .WithMemoryCache (r .Storage .LocalPath (* repo .GetArtifact ()), r .Cache , r .TTL , func (event string ) {
656
- r .IncCacheEvents (event , obj .Name , obj .Namespace )
657
- }))
656
+ httpChartRepo , err := repository .NewChartRepository (normalizedURL , r .Storage .LocalPath (* repo .GetArtifact ()), r .Getters , tlsConfig , clientOpts ... )
658
657
if err != nil {
659
658
return chartRepoConfigErrorReturn (err , obj )
660
659
}
661
660
chartRepo = httpChartRepo
662
661
defer func () {
663
- if httpChartRepo == nil {
664
- return
665
- }
666
662
// Cache the index if it was successfully retrieved
667
- // and the chart was successfully built
663
+ // and the chart was successfully built.
668
664
if r .Cache != nil && httpChartRepo .Index != nil {
669
- // The cache key have to be safe in multi-tenancy environments,
670
- // as otherwise it could be used as a vector to bypass the helm repository's authentication.
671
- // Using r.Storage.LocalPath(*repo.GetArtifact() is safe as the path is in the format /<helm-repository-name>/<chart-name>/<filename>.
672
- err := httpChartRepo .CacheIndexInMemory ()
673
- if err != nil {
665
+ // The cache key has to be safe in multi-tenancy environments,
666
+ // as otherwise it could be used as a vector to bypass
667
+ // authentication to the repository.
668
+ // Using r.Storage.LocalPath(*repo.GetArtifact()) is safe as the
669
+ // path is in the format of: /<repository-name>/<chart-name>/<filename>.
670
+ if err = r .Cache .Set (r .Storage .LocalPath (* repo .GetArtifact ()), httpChartRepo .Index , r .TTL ); err != nil {
674
671
r .eventLogf (ctx , obj , eventv1 .EventTypeTrace , sourcev1 .CacheOperationFailedReason , "failed to cache index: %s" , err )
675
672
}
676
673
}
677
-
678
674
// Delete the index reference
679
- if httpChartRepo .Index != nil {
680
- httpChartRepo .Unload ()
681
- }
675
+ httpChartRepo .Clear ()
682
676
}()
683
677
}
684
678
@@ -845,7 +839,7 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj
845
839
// early.
846
840
// On a successful archive, the Artifact in the Status of the object is set,
847
841
// and the symlink in the Storage is updated to its path.
848
- func (r * HelmChartReconciler ) reconcileArtifact (ctx context.Context , sp * patch.SerialPatcher , obj * sourcev1.HelmChart , b * chart.Build ) (sreconcile.Result , error ) {
842
+ func (r * HelmChartReconciler ) reconcileArtifact (ctx context.Context , _ * patch.SerialPatcher , obj * sourcev1.HelmChart , b * chart.Build ) (sreconcile.Result , error ) {
849
843
// Without a complete chart build, there is little to reconcile
850
844
if ! b .Complete () {
851
845
return sreconcile .ResultRequeue , nil
@@ -1016,14 +1010,15 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
1016
1010
authenticator authn.Authenticator
1017
1011
keychain authn.Keychain
1018
1012
)
1013
+
1019
1014
normalizedURL := repository .NormalizeURL (url )
1020
- repo , err := r .resolveDependencyRepository (ctx , url , namespace )
1015
+ obj , err := r .resolveDependencyRepository (ctx , url , namespace )
1021
1016
if err != nil {
1022
1017
// Return Kubernetes client errors, but ignore others
1023
1018
if apierrs .ReasonForError (err ) != metav1 .StatusReasonUnknown {
1024
1019
return nil , err
1025
1020
}
1026
- repo = & sourcev1.HelmRepository {
1021
+ obj = & sourcev1.HelmRepository {
1027
1022
Spec : sourcev1.HelmRepositorySpec {
1028
1023
URL : url ,
1029
1024
Timeout : & metav1.Duration {Duration : 60 * time .Second },
@@ -1032,37 +1027,37 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
1032
1027
}
1033
1028
1034
1029
// Used to login with the repository declared provider
1035
- ctxTimeout , cancel := context .WithTimeout (ctx , repo .Spec .Timeout .Duration )
1030
+ ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
1036
1031
defer cancel ()
1037
1032
1038
1033
clientOpts := []helmgetter.Option {
1039
1034
helmgetter .WithURL (normalizedURL ),
1040
- helmgetter .WithTimeout (repo .Spec .Timeout .Duration ),
1041
- helmgetter .WithPassCredentialsAll (repo .Spec .PassCredentials ),
1035
+ helmgetter .WithTimeout (obj .Spec .Timeout .Duration ),
1036
+ helmgetter .WithPassCredentialsAll (obj .Spec .PassCredentials ),
1042
1037
}
1043
- if secret , err := r .getHelmRepositorySecret (ctx , repo ); secret != nil || err != nil {
1038
+ if secret , err := r .getHelmRepositorySecret (ctx , obj ); secret != nil || err != nil {
1044
1039
if err != nil {
1045
1040
return nil , err
1046
1041
}
1047
1042
1048
1043
// Build client options from secret
1049
- opts , tls , err := r .clientOptionsFromSecret (secret , normalizedURL )
1044
+ opts , tlsCfg , err := r .clientOptionsFromSecret (secret , normalizedURL )
1050
1045
if err != nil {
1051
1046
return nil , err
1052
1047
}
1053
1048
clientOpts = append (clientOpts , opts ... )
1054
- tlsConfig = tls
1049
+ tlsConfig = tlsCfg
1055
1050
1056
1051
// Build registryClient options from secret
1057
1052
keychain , err = registry .LoginOptionFromSecret (normalizedURL , * secret )
1058
1053
if err != nil {
1059
- return nil , fmt .Errorf ("failed to create login options for HelmRepository '%s': %w" , repo .Name , err )
1054
+ return nil , fmt .Errorf ("failed to create login options for HelmRepository '%s': %w" , obj .Name , err )
1060
1055
}
1061
1056
1062
- } else if repo .Spec .Provider != sourcev1 .GenericOCIProvider && repo .Spec .Type == sourcev1 .HelmRepositoryTypeOCI {
1063
- auth , authErr := oidcAuth (ctxTimeout , repo .Spec .URL , repo .Spec .Provider )
1057
+ } else if obj .Spec .Provider != sourcev1 .GenericOCIProvider && obj .Spec .Type == sourcev1 .HelmRepositoryTypeOCI {
1058
+ auth , authErr := oidcAuth (ctxTimeout , obj .Spec .URL , obj .Spec .Provider )
1064
1059
if authErr != nil && ! errors .Is (authErr , oci .ErrUnconfiguredProvider ) {
1065
- return nil , fmt .Errorf ("failed to get credential from %s: %w" , repo .Spec .Provider , authErr )
1060
+ return nil , fmt .Errorf ("failed to get credential from %s: %w" , obj .Spec .Provider , authErr )
1066
1061
}
1067
1062
if auth != nil {
1068
1063
authenticator = auth
@@ -1078,7 +1073,7 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
1078
1073
if helmreg .IsOCI (normalizedURL ) {
1079
1074
registryClient , credentialsFile , err := r .RegistryClientGenerator (loginOpt != nil )
1080
1075
if err != nil {
1081
- return nil , fmt .Errorf ("failed to create registry client for HelmRepository '%s': %w" , repo .Name , err )
1076
+ return nil , fmt .Errorf ("failed to create registry client for HelmRepository '%s': %w" , obj .Name , err )
1082
1077
}
1083
1078
1084
1079
var errs []error
@@ -1089,7 +1084,7 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
1089
1084
repository .WithOCIRegistryClient (registryClient ),
1090
1085
repository .WithCredentialsFile (credentialsFile ))
1091
1086
if err != nil {
1092
- errs = append (errs , fmt .Errorf ("failed to create OCI chart repository for HelmRepository '%s': %w" , repo .Name , err ))
1087
+ errs = append (errs , fmt .Errorf ("failed to create OCI chart repository for HelmRepository '%s': %w" , obj .Name , err ))
1093
1088
// clean up the credentialsFile
1094
1089
if credentialsFile != "" {
1095
1090
if err := os .Remove (credentialsFile ); err != nil {
@@ -1104,7 +1099,7 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
1104
1099
if loginOpt != nil {
1105
1100
err = ociChartRepo .Login (loginOpt )
1106
1101
if err != nil {
1107
- errs = append (errs , fmt .Errorf ("failed to login to OCI chart repository for HelmRepository '%s': %w" , repo .Name , err ))
1102
+ errs = append (errs , fmt .Errorf ("failed to login to OCI chart repository for HelmRepository '%s': %w" , obj .Name , err ))
1108
1103
// clean up the credentialsFile
1109
1104
errs = append (errs , ociChartRepo .Clear ())
1110
1105
return nil , kerrors .NewAggregate (errs )
@@ -1113,19 +1108,28 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
1113
1108
1114
1109
chartRepo = ociChartRepo
1115
1110
} else {
1116
- httpChartRepo , err := repository .NewChartRepository (normalizedURL , "" , r .Getters , tlsConfig , clientOpts )
1111
+ httpChartRepo , err := repository .NewChartRepository (normalizedURL , "" , r .Getters , tlsConfig , clientOpts ... )
1117
1112
if err != nil {
1118
1113
return nil , err
1119
1114
}
1120
1115
1121
- // Ensure that the cache key is the same as the artifact path
1122
- // otherwise don't enable caching. We don't want to cache indexes
1123
- // for repositories that are not reconciled by the source controller.
1124
- if repo .Status .Artifact != nil {
1125
- httpChartRepo .CachePath = r .Storage .LocalPath (* repo .GetArtifact ())
1126
- httpChartRepo .SetMemCache (r .Storage .LocalPath (* repo .GetArtifact ()), r .Cache , r .TTL , func (event string ) {
1127
- r .IncCacheEvents (event , name , namespace )
1128
- })
1116
+ if obj .Status .Artifact != nil {
1117
+ // Attempt to load the index from the cache.
1118
+ httpChartRepo .Path = r .Storage .LocalPath (* obj .GetArtifact ())
1119
+ if r .Cache != nil {
1120
+ if index , ok := r .Cache .Get (httpChartRepo .Path ); ok {
1121
+ r .IncCacheEvents (cache .CacheEventTypeHit , name , namespace )
1122
+ r .Cache .SetExpiration (httpChartRepo .Path , r .TTL )
1123
+
1124
+ httpChartRepo .Index = index .(* helmrepo.IndexFile )
1125
+ } else {
1126
+ r .IncCacheEvents (cache .CacheEventTypeMiss , name , namespace )
1127
+ if err := httpChartRepo .LoadFromPath (); err != nil {
1128
+ return nil , err
1129
+ }
1130
+ r .Cache .Set (httpChartRepo .Path , httpChartRepo .Index , r .TTL )
1131
+ }
1132
+ }
1129
1133
}
1130
1134
1131
1135
chartRepo = httpChartRepo
0 commit comments