Skip to content

Commit cf5c51c

Browse files
authored
Refactor follower behavior for ClusterRepos handler (rancher#54161)
1 parent af41a67 commit cf5c51c

3 files changed

Lines changed: 42 additions & 26 deletions

File tree

pkg/catalogv2/git/download.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import (
88
corev1 "k8s.io/api/core/v1"
99
)
1010

11-
// Ensure runs git clone, clean DIRTY contents and fetch the latest commit
11+
// Ensure the repository is checked out at the provided commit reference.
12+
// Cloning/fetching and cleaning a dirty state is performed if necessary
1213
func Ensure(secret *corev1.Secret, namespace, name, gitURL, commit string, insecureSkipTLS bool, caBundle []byte) error {
1314
git, err := gitForRepo(secret, namespace, name, gitURL, insecureSkipTLS, caBundle)
1415
if err != nil {

pkg/controllers/dashboard/helm/repo.go

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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
7376
func 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

100106
func (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+
153173
func 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

253268
func (r *repoHandler) download(repository *catalog.ClusterRepo, newStatus *catalog.RepoStatus, owner metav1.OwnerReference, interval time.Duration, retryPolicy retryPolicy) (*catalog.ClusterRepo, error) {

pkg/controllers/dashboard/helm/repo_oci.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ func (o *OCIRepohandler) onClusterRepoChange(key string, clusterRepo *catalog.Cl
121121
var index *repo.IndexFile
122122

123123
// If repo is disabled, then don't update the clusterrepo
124-
if clusterRepo.Spec.Enabled != nil && !*clusterRepo.Spec.Enabled {
125-
return setErrorCondition(clusterRepo, err, newStatus, ociInterval, ociCondition, o.clusterRepoController)
124+
if isDisabled(clusterRepo) {
125+
return setErrorCondition(clusterRepo, nil, newStatus, ociInterval, ociCondition, o.clusterRepoController)
126126
}
127127

128128
secret, err := catalogv2.GetSecret(o.secretCacheController, &clusterRepo.Spec, clusterRepo.Namespace)

0 commit comments

Comments
 (0)