Skip to content

Commit

Permalink
refactor: add indexes to secret informers to speedup settings parsing (
Browse files Browse the repository at this point in the history
…#7882)

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
  • Loading branch information
Alexander Matyushentsev committed Dec 7, 2021
1 parent b813301 commit bea379b
Show file tree
Hide file tree
Showing 11 changed files with 258 additions and 113 deletions.
29 changes: 21 additions & 8 deletions controller/appcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,19 +166,26 @@ func NewApplicationController(
AddFunc: func(obj interface{}) {
if key, err := cache.MetaNamespaceKeyFunc(obj); err == nil {
ctrl.projectRefreshQueue.Add(key)
ctrl.InvalidateProjectsCache()
if projMeta, ok := obj.(metav1.Object); ok {
ctrl.InvalidateProjectsCache(projMeta.GetName())
}

}
},
UpdateFunc: func(old, new interface{}) {
if key, err := cache.MetaNamespaceKeyFunc(new); err == nil {
ctrl.projectRefreshQueue.Add(key)
ctrl.InvalidateProjectsCache()
if projMeta, ok := new.(metav1.Object); ok {
ctrl.InvalidateProjectsCache(projMeta.GetName())
}
}
},
DeleteFunc: func(obj interface{}) {
if key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj); err == nil {
ctrl.projectRefreshQueue.Add(key)
ctrl.InvalidateProjectsCache()
if projMeta, ok := obj.(metav1.Object); ok {
ctrl.InvalidateProjectsCache(projMeta.GetName())
}
}
},
})
Expand Down Expand Up @@ -207,11 +214,17 @@ func NewApplicationController(
return &ctrl, nil
}

func (ctrl *ApplicationController) InvalidateProjectsCache() {
ctrl.projByNameCache.Range(func(key, _ interface{}) bool {
ctrl.projByNameCache.Delete(key)
return true
})
func (ctrl *ApplicationController) InvalidateProjectsCache(names ...string) {
if len(names) > 0 {
for _, name := range names {
ctrl.projByNameCache.Delete(name)
}
} else {
ctrl.projByNameCache.Range(func(key, _ interface{}) bool {
ctrl.projByNameCache.Delete(key)
return true
})
}
}

func (ctrl *ApplicationController) GetMetricsServer() *metrics.MetricsServer {
Expand Down
4 changes: 2 additions & 2 deletions server/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ func (s *Server) CreateRepository(ctx context.Context, q *repositorypkg.RepoCrea
var repo *appsv1.Repository
var err error

// check we can connect to the repo, copying any existing creds
{
// check we can connect to the repo, copying any existing creds (not supported for project scoped repositories)
if q.Repo.Project == "" {
repo := q.Repo.DeepCopy()
if !repo.HasCredentials() {
creds, err := s.db.GetRepositoryCredentials(ctx, repo.Repo)
Expand Down
48 changes: 17 additions & 31 deletions util/argo/argo.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,34 +396,6 @@ func APIResourcesToStrings(resources []kube.APIResourceInfo, includeKinds bool)
return res
}

func retrieveScopedRepositories(name string, db db.ArgoDB, ctx context.Context) []*argoappv1.Repository {
var repositories []*argoappv1.Repository
allRepos, err := db.ListRepositories(ctx)
if err != nil {
return repositories
}
for _, repo := range allRepos {
if repo.Project == name {
repositories = append(repositories, repo)
}
}
return repositories
}

func retrieveScopedClusters(name string, db db.ArgoDB, ctx context.Context) []*argoappv1.Cluster {
var clusters []*argoappv1.Cluster
allClusters, err := db.ListClusters(ctx)
if err != nil {
return clusters
}
for i, cluster := range allClusters.Items {
if cluster.Project == name {
clusters = append(clusters, &allClusters.Items[i])
}
}
return clusters
}

// GetAppProjectWithScopedResources returns a project from an application with scoped resources
func GetAppProjectWithScopedResources(name string, projLister applicationsv1.AppProjectLister, ns string, settingsManager *settings.SettingsManager, db db.ArgoDB, ctx context.Context) (*argoappv1.AppProject, argoappv1.Repositories, []*argoappv1.Cluster, error) {
projOrig, err := projLister.AppProjects(ns).Get(name)
Expand All @@ -437,7 +409,15 @@ func GetAppProjectWithScopedResources(name string, projLister applicationsv1.App
return nil, nil, nil, err
}

return project, retrieveScopedRepositories(name, db, ctx), retrieveScopedClusters(name, db, ctx), nil
clusters, err := db.GetProjectClusters(ctx, project.Name)
if err != nil {
return nil, nil, nil, err
}
repos, err := db.GetProjectRepositories(ctx, name)
if err != nil {
return nil, nil, nil, err
}
return project, repos, clusters, nil

}

Expand All @@ -448,11 +428,17 @@ func GetAppProjectByName(name string, projLister applicationsv1.AppProjectLister
return nil, err
}
project := projOrig.DeepCopy()
repos := retrieveScopedRepositories(name, db, ctx)
repos, err := db.GetProjectRepositories(ctx, name)
if err != nil {
return nil, err
}
for _, repo := range repos {
project.Spec.SourceRepos = append(project.Spec.SourceRepos, repo.Repo)
}
clusters := retrieveScopedClusters(name, db, ctx)
clusters, err := db.GetProjectClusters(ctx, name)
if err != nil {
return nil, err
}
for _, cluster := range clusters {
if len(cluster.Namespaces) == 0 {
project.Spec.Destinations = append(project.Spec.Destinations, argoappv1.ApplicationDestination{Server: cluster.Server, Namespace: "*"})
Expand Down
33 changes: 0 additions & 33 deletions util/argo/argo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -891,39 +891,6 @@ func TestGetGlobalProjects(t *testing.T) {
})
}

func Test_retrieveScopedRepositories(t *testing.T) {
repo := &argoappv1.Repository{Repo: fmt.Sprintf("file://%s", "test"), Project: "test"}

repos := make([]*argoappv1.Repository, 0)
repos = append(repos, repo)

db := &dbmocks.ArgoDB{}

db.On("ListRepositories", context.TODO()).Return(repos, nil)

scopedRepos := retrieveScopedRepositories("test", db, context.TODO())

assert.Len(t, scopedRepos, 1)
assert.Equal(t, scopedRepos[0].Repo, repo.Repo)

}

func Test_retrieveScopedRepositoriesWithNotProjectAssigned(t *testing.T) {
repo := &argoappv1.Repository{Repo: fmt.Sprintf("file://%s", "test")}

repos := make([]*argoappv1.Repository, 0)
repos = append(repos, repo)

db := &dbmocks.ArgoDB{}

db.On("ListRepositories", context.TODO()).Return(repos, nil)

scopedRepos := retrieveScopedRepositories("test", db, context.TODO())

assert.Len(t, scopedRepos, 0)

}

func Test_GetDifferentPathsBetweenStructs(t *testing.T) {

r1 := argoappv1.Repository{}
Expand Down
43 changes: 29 additions & 14 deletions util/db/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/argoproj/argo-cd/v2/common"
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/collections"
"github.com/argoproj/argo-cd/v2/util/settings"
)

var (
Expand Down Expand Up @@ -190,31 +191,45 @@ func (db *db) getClusterSecret(server string) (*apiv1.Secret, error) {
return nil, status.Errorf(codes.NotFound, "cluster %q not found", server)
}

func (db *db) getClusterFromSecret(server string) (*appv1.Cluster, error) {
clusterSecrets, err := db.listSecretsByType(common.LabelValueSecretTypeCluster)
// GetCluster returns a cluster from a query
func (db *db) GetCluster(_ context.Context, server string) (*appv1.Cluster, error) {
informer, err := db.settingsMgr.GetSecretsInformer()
if err != nil {
return nil, err
}
srv := strings.TrimRight(server, "/")
for _, clusterSecret := range clusterSecrets {
if strings.TrimRight(string(clusterSecret.Data["server"]), "/") == srv {
return secretToCluster(clusterSecret)
}
res, err := informer.GetIndexer().ByIndex(settings.ByClusterURLIndexer, server)
if err != nil {
return nil, err
}
if len(res) > 0 {
return secretToCluster(res[0].(*apiv1.Secret))
}
if server == appv1.KubernetesInternalAPIServerAddr {
return db.getLocalCluster(), nil
}

return nil, status.Errorf(codes.NotFound, "cluster %q not found", server)
}

// GetCluster returns a cluster from a query
func (db *db) GetCluster(_ context.Context, server string) (*appv1.Cluster, error) {
cluster, err := db.getClusterFromSecret(server)
// GetProjectClusters return project scoped clusters by given project name
func (db *db) GetProjectClusters(ctx context.Context, project string) ([]*appv1.Cluster, error) {
informer, err := db.settingsMgr.GetSecretsInformer()
if err != nil {
if errorStatus, ok := status.FromError(err); ok && errorStatus.Code() == codes.NotFound && server == appv1.KubernetesInternalAPIServerAddr {
return db.getLocalCluster(), nil
} else {
return nil, err
}
secrets, err := informer.GetIndexer().ByIndex(settings.ByProjectClusterIndexer, project)
if err != nil {
return nil, err
}
var res []*appv1.Cluster
for i := range secrets {
cluster, err := secretToCluster(secrets[i].(*apiv1.Secret))
if err != nil {
return nil, err
}
res = append(res, cluster)
}
return cluster, nil
return res, nil
}

// UpdateCluster updates a cluster
Expand Down
6 changes: 5 additions & 1 deletion util/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ type ArgoDB interface {
handleAddEvent func(cluster *appv1.Cluster),
handleModEvent func(oldCluster *appv1.Cluster, newCluster *appv1.Cluster),
handleDeleteEvent func(clusterServer string)) error
// Get returns a cluster from a query
// GetCluster get returns a cluster by given server url
GetCluster(ctx context.Context, server string) (*appv1.Cluster, error)
// GetProjectClusters return project scoped clusters by given project name
GetProjectClusters(ctx context.Context, project string) ([]*appv1.Cluster, error)
// UpdateCluster updates a cluster
UpdateCluster(ctx context.Context, c *appv1.Cluster) (*appv1.Cluster, error)
// DeleteCluster deletes a cluster by name
Expand All @@ -41,6 +43,8 @@ type ArgoDB interface {
CreateRepository(ctx context.Context, r *appv1.Repository) (*appv1.Repository, error)
// GetRepository returns a repository by URL
GetRepository(ctx context.Context, url string) (*appv1.Repository, error)
// GetProjectRepositories returns project scoped repositories by given project name
GetProjectRepositories(ctx context.Context, project string) ([]*appv1.Repository, error)
// RepositoryExists returns whether a repository is configured for the given URL
RepositoryExists(ctx context.Context, repoURL string) (bool, error)
// UpdateRepository updates a repository
Expand Down
72 changes: 58 additions & 14 deletions util/db/mocks/ArgoDB.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit bea379b

Please sign in to comment.