@@ -8,8 +8,10 @@ import (
88 "errors"
99 "fmt"
1010 "os"
11+ "slices"
1112 "time"
1213
14+ "github.com/rancher/wrangler/v3/pkg/genericcondition"
1315 "k8s.io/apimachinery/pkg/api/equality"
1416
1517 catalog "github.com/rancher/rancher/pkg/apis/catalog.cattle.io/v1"
@@ -70,6 +72,7 @@ func RegisterRepos(ctx context.Context,
7072
7173}
7274
75+ // RegisterReposForFollowers need to run on every replica (including the leader), see comment on EnsureRepositoryCheckout
7376func RegisterReposForFollowers (ctx context.Context ,
7477 secrets corev1controllers.SecretCache ,
7578 clusterRepos catalogcontrollers.ClusterRepoController ) {
@@ -78,23 +81,26 @@ func RegisterReposForFollowers(ctx context.Context,
7881 clusterRepos : clusterRepos ,
7982 }
8083
81- catalogcontrollers .RegisterClusterRepoStatusHandler (ctx , clusterRepos ,
82- condition .Cond (catalog .FollowerRepoDownloaded ), "helm-clusterrepo-ensure" , h .ClusterRepoDownloadEnsureStatusHandler )
83-
84+ clusterRepos .OnChange (ctx , "helm-clusterrepo-ensure" , h .EnsureRepositoryCheckout )
8485}
8586
86- func (r * repoHandler ) ClusterRepoDownloadEnsureStatusHandler (repo * catalog.ClusterRepo , status catalog.RepoStatus ) (catalog.RepoStatus , error ) {
87+ // EnsureRepositoryCheckout will fetch and/or initialize the necessary data to ensure the corresponding git repositories match commit in the status
88+ // .status.commit is only updated by the leader, but this needs to run in all replicas, including the leader despite being redundant, to ensure repositories are correctly initialized after a restart
89+ func (r * repoHandler ) EnsureRepositoryCheckout (_ string , repo * catalog.ClusterRepo ) (* catalog.ClusterRepo , error ) {
90+ if repo == nil {
91+ return nil , nil
92+ }
8793 if registry .IsOCI (repo .Spec .URL ) {
88- return status , nil
94+ return repo , nil
8995 }
9096
91- interval := defaultInterval
92- if repo .Spec .RefreshInterval > 0 {
93- interval = time .Duration (repo .Spec .RefreshInterval ) * time .Second
97+ if isDisabled (repo ) || repo .Status .Commit == "" {
98+ return repo , nil
9499 }
95100
96- r .clusterRepos .EnqueueAfter (repo .Name , interval )
97- return r .ensure (& repo .Spec , status , & repo .ObjectMeta )
101+ // Sync the followers' repository copy to the commit observed by the leader
102+ err := r .ensure (repo )
103+ return repo , err
98104}
99105
100106func (r * repoHandler ) ClusterRepoOnChange (key string , repo * catalog.ClusterRepo ) (* catalog.ClusterRepo , error ) {
@@ -119,6 +125,8 @@ func (r *repoHandler) ClusterRepoOnChange(key string, repo *catalog.ClusterRepo)
119125 }
120126
121127 newStatus := repo .Status .DeepCopy ()
128+ removeLegacyCondition (newStatus )
129+
122130 retryPolicy , err := getRetryPolicy (repo )
123131 if err != nil {
124132 err = fmt .Errorf ("failed to get retry policy: %w" , err )
@@ -137,9 +145,9 @@ func (r *repoHandler) ClusterRepoOnChange(key string, repo *catalog.ClusterRepo)
137145 newStatus .ShouldNotSkip = false
138146
139147 // If repo is disabled, then don't update the clusterrepo
140- if repo . Spec . Enabled != nil && ! * repo . Spec . Enabled {
148+ if isDisabled ( repo ) {
141149 logrus .Infof ("skipping repo %s because it is disabled" , repo .Name )
142- return setErrorCondition (repo , err , newStatus , interval , ociCondition , r .clusterRepos )
150+ return setErrorCondition (repo , nil , newStatus , interval , repoCondition , r .clusterRepos )
143151 }
144152
145153 return r .download (repo , newStatus , metav1.OwnerReference {
@@ -150,6 +158,18 @@ func (r *repoHandler) ClusterRepoOnChange(key string, repo *catalog.ClusterRepo)
150158 }, interval , retryPolicy )
151159}
152160
161+ func isDisabled (repo * catalog.ClusterRepo ) bool {
162+ return repo != nil && repo .Spec .Enabled != nil && ! * repo .Spec .Enabled
163+ }
164+
165+ func removeLegacyCondition (status * catalog.RepoStatus ) {
166+ if n := slices .IndexFunc (status .Conditions , func (cond genericcondition.GenericCondition ) bool {
167+ return cond .Type == "FollowerDownloaded"
168+ }); n >= 0 {
169+ status .Conditions = append (status .Conditions [:n ], status .Conditions [n + 1 :]... )
170+ }
171+ }
172+
153173func toOwnerObject (namespace string , owner metav1.OwnerReference ) runtime.Object {
154174 return & metav1.PartialObjectMetadata {
155175 TypeMeta : metav1.TypeMeta {
@@ -232,22 +252,17 @@ func createOrUpdateMap(namespace string, index *repo.IndexFile, owner metav1.Own
232252 return objs [0 ].(* corev1.ConfigMap ), err
233253}
234254
235- func (r * repoHandler ) ensure (repoSpec * catalog.RepoSpec , status catalog.RepoStatus , metadata * metav1.ObjectMeta ) (catalog.RepoStatus , error ) {
236- if status .Commit == "" {
237- return status , nil
238- }
239-
240- // If repo is disabled, skip updating the replicas.
241- if repoSpec .Enabled != nil && ! * repoSpec .Enabled {
242- return status , nil
255+ func (r * repoHandler ) ensure (repo * catalog.ClusterRepo ) error {
256+ if repo .Status .Commit == "" {
257+ return nil
243258 }
244259
245- secret , err := catalogv2 .GetSecret (r .secrets , repoSpec , metadata .Namespace )
260+ secret , err := catalogv2 .GetSecret (r .secrets , & repo . Spec , repo .Namespace )
246261 if err != nil {
247- return status , err
262+ return err
248263 }
249264
250- return status , git .Ensure (secret , metadata .Namespace , metadata .Name , status . URL , status . Commit , repoSpec . InsecureSkipTLSverify , repoSpec .CABundle )
265+ return git .Ensure (secret , repo .Namespace , repo .Name , repo . Status . URL , repo . Status . Commit , repo . Spec . InsecureSkipTLSverify , repo . Spec .CABundle )
251266}
252267
253268func (r * repoHandler ) download (repository * catalog.ClusterRepo , newStatus * catalog.RepoStatus , owner metav1.OwnerReference , interval time.Duration , retryPolicy retryPolicy ) (* catalog.ClusterRepo , error ) {
0 commit comments