Skip to content

Commit

Permalink
React to secrets referenced by GitRepos changes
Browse files Browse the repository at this point in the history
  • Loading branch information
bastjan committed Jul 17, 2024
1 parent b36edb7 commit 5192a97
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 2 deletions.
62 changes: 62 additions & 0 deletions controllers/gitrepo/watchers/ci_var_secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package watchers

import (
"context"

corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

synv1alpha1 "github.com/projectsyn/lieutenant-operator/api/v1alpha1"
)

const (
// GitRepoCIVariableValueFromSecretKeyRefNameIndex is the index name for the GitRepo objects that reference a secret by name.
GitRepoCIVariableValueFromSecretKeyRefNameIndex = "spec.ciVariables.valueFrom.secretKeyRef.name"
)

// SecretGitRepoCIVariablesMapFunc returns a handler function that will return a list of reconcile.Requests for GitRepo objects
// that reference the secret in the given Secret object.
// It requires the field index GitRepoCIVariableValueFromSecretKeyRefNameIndex to be installed for the GitRepo objects.
func SecretGitRepoCIVariablesMapFunc(cli client.Client) func(ctx context.Context, o client.Object) []reconcile.Request {
return func(ctx context.Context, o client.Object) []reconcile.Request {
l := log.FromContext(ctx).WithName("SecretGitRepoCIVariablesMapFunc").WithValues("secret", o.GetName())

secret := o.(*corev1.Secret)
var gitRepos synv1alpha1.GitRepoList
if err := cli.List(ctx, &gitRepos, client.MatchingFields{
GitRepoCIVariableValueFromSecretKeyRefNameIndex: secret.Name,
}, client.InNamespace(secret.GetNamespace())); err != nil {
l.Error(err, "unable to list GitRepos")
return []reconcile.Request{}
}

requests := make([]reconcile.Request, 0, len(gitRepos.Items))
for _, gitRepo := range gitRepos.Items {
requests = append(requests, reconcile.Request{
NamespacedName: client.ObjectKey{
Namespace: gitRepo.Namespace,
Name: gitRepo.Name,
},
})
}

return requests
}
}

// GitRepoCIVariableValueFromSecretKeyRefNameIndexFunc is an index function for GitRepo objects.
// It indexes the names of the secrets that are referenced by the CIVariables of the GitRepo.
func GitRepoCIVariableValueFromSecretKeyRefNameIndexFunc(obj client.Object) []string {
gitRepo := obj.(*synv1alpha1.GitRepo)
values := make([]string, 0, len(gitRepo.Spec.CIVariables))
for _, ciVariable := range gitRepo.Spec.CIVariables {
if ciVariable.ValueFrom != nil &&
ciVariable.ValueFrom.SecretKeyRef != nil &&
ciVariable.ValueFrom.SecretKeyRef.Name != "" {
values = append(values, ciVariable.ValueFrom.SecretKeyRef.Name)
}
}
return values
}
158 changes: 158 additions & 0 deletions controllers/gitrepo/watchers/ci_var_secret_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package watchers_test

import (
"context"
"testing"

"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client/fake"

synv1alpha1 "github.com/projectsyn/lieutenant-operator/api/v1alpha1"
"github.com/projectsyn/lieutenant-operator/controllers/gitrepo/watchers"
)

func TestIndexAndMapFunc(t *testing.T) {
scheme := runtime.NewScheme()
require.NoError(t, clientgoscheme.AddToScheme(scheme))
require.NoError(t, synv1alpha1.AddToScheme(scheme))

defaultNs := "test-namespace"

secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "important-ci-stuff",
Namespace: defaultNs,
},
Data: map[string][]byte{
"key": []byte("value"),
},
}
secret2 := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "important-ci-stuff-too",
Namespace: defaultNs,
},
Data: map[string][]byte{
"key": []byte("value"),
},
}

repoWithSecretRef := &synv1alpha1.GitRepo{
ObjectMeta: metav1.ObjectMeta{
Name: "repo-with-secret-ref",
Namespace: secret.GetNamespace(),
},
Spec: synv1alpha1.GitRepoSpec{
GitRepoTemplate: synv1alpha1.GitRepoTemplate{
CIVariables: []synv1alpha1.EnvVar{
{
Name: "KEY",
Value: "value",
},
{
Name: "SECRET",
ValueFrom: &synv1alpha1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secret.Name,
},
Key: "key",
},
},
},
{
Name: "SECRET2",
ValueFrom: &synv1alpha1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secret2.Name,
},
Key: "key",
},
},
},
},
},
},
}
repoWithOtherSecretRef := &synv1alpha1.GitRepo{
ObjectMeta: metav1.ObjectMeta{
Name: "repo-with-other-secret-ref",
Namespace: secret.GetNamespace(),
},
Spec: synv1alpha1.GitRepoSpec{
GitRepoTemplate: synv1alpha1.GitRepoTemplate{
CIVariables: []synv1alpha1.EnvVar{
{
Name: "KEY",
Value: "value",
},
{
Name: "SECRET",
ValueFrom: &synv1alpha1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "other-secret",
},
Key: "key",
},
},
},
},
},
},
}
repoWithSecretRefInOtherNs := &synv1alpha1.GitRepo{
ObjectMeta: metav1.ObjectMeta{
Name: "repo-with-secret-ref-in-other-ns",
Namespace: "other-namespace",
},
Spec: synv1alpha1.GitRepoSpec{
GitRepoTemplate: synv1alpha1.GitRepoTemplate{
CIVariables: []synv1alpha1.EnvVar{
{
Name: "KEY",
Value: "value",
},
{
Name: "SECRET",
ValueFrom: &synv1alpha1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "other-secret",
},
Key: "key",
},
},
},
},
},
},
}
repoWithoutRef := &synv1alpha1.GitRepo{
ObjectMeta: metav1.ObjectMeta{
Name: "repo-without-ref",
Namespace: defaultNs,
},
Spec: synv1alpha1.GitRepoSpec{
GitRepoTemplate: synv1alpha1.GitRepoTemplate{},
},
}

c := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(secret, secret2, repoWithSecretRef, repoWithOtherSecretRef, repoWithSecretRefInOtherNs, repoWithoutRef).
WithIndex(&synv1alpha1.GitRepo{}, watchers.GitRepoCIVariableValueFromSecretKeyRefNameIndex, watchers.GitRepoCIVariableValueFromSecretKeyRefNameIndexFunc).
Build()

requests := watchers.SecretGitRepoCIVariablesMapFunc(c)(context.Background(), secret)
require.Len(t, requests, 1)
require.Equal(t, repoWithSecretRef.Name, requests[0].Name)
requests = watchers.SecretGitRepoCIVariablesMapFunc(c)(context.Background(), secret2)
require.Len(t, requests, 1)
require.Equal(t, repoWithSecretRef.Name, requests[0].Name)
}
19 changes: 18 additions & 1 deletion controllers/gitrepo_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ package controllers

import (
"context"
"fmt"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

synv1alpha1 "github.com/projectsyn/lieutenant-operator/api/v1alpha1"
"github.com/projectsyn/lieutenant-operator/controllers/gitrepo"
"github.com/projectsyn/lieutenant-operator/controllers/gitrepo/watchers"
"github.com/projectsyn/lieutenant-operator/pipeline"
)

Expand Down Expand Up @@ -71,9 +74,23 @@ func (r *GitRepoReconciler) Reconcile(ctx context.Context, request ctrl.Request)
}

// SetupWithManager sets up the controller with the Manager.
func (r *GitRepoReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *GitRepoReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error {
err := mgr.GetFieldIndexer().IndexField(
ctx,
&synv1alpha1.GitRepo{},
watchers.GitRepoCIVariableValueFromSecretKeyRefNameIndex,
watchers.GitRepoCIVariableValueFromSecretKeyRefNameIndexFunc,
)
if err != nil {
return fmt.Errorf("unable to create index for GitRepo: %w", err)
}

return ctrl.NewControllerManagedBy(mgr).
For(&synv1alpha1.GitRepo{}).
Owns(&corev1.Secret{}).
Watches(
&corev1.Secret{},
handler.EnqueueRequestsFromMapFunc(watchers.SecretGitRepoCIVariablesMapFunc(mgr.GetClient())),
).
Complete(r)
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func main() {
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
DefaultCreationPolicy: creationPolicy,
}).SetupWithManager(mgr); err != nil {
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitRepo")
os.Exit(1)
}
Expand Down

0 comments on commit 5192a97

Please sign in to comment.