From b79e77b6abb11c66058b1c52a53f4dd98bd36aea Mon Sep 17 00:00:00 2001 From: Henning Eggers Date: Mon, 17 Apr 2023 11:04:51 +0200 Subject: [PATCH] feat: add watch-namespaces option (#13) * feat: add --watch-namespaces option * fix: push image from pr WIP --- .github/workflows/test_pr.yml | 25 --------- .github/workflows/test_push_pr.yml | 54 +++++++++++++++++++ Containerile => Containerfile | 0 Makefile | 4 +- cmd/main.go | 17 ++++-- .../awsauthmapsnippet_controller.go | 10 ++++ pkg/predicates/predicates.go | 22 ++++++++ pkg/predicates/predicates_test.go | 44 +++++++++++++++ 8 files changed, 146 insertions(+), 30 deletions(-) delete mode 100644 .github/workflows/test_pr.yml create mode 100644 .github/workflows/test_push_pr.yml rename Containerile => Containerfile (100%) create mode 100644 pkg/predicates/predicates.go create mode 100644 pkg/predicates/predicates_test.go diff --git a/.github/workflows/test_pr.yml b/.github/workflows/test_pr.yml deleted file mode 100644 index 7d4f576..0000000 --- a/.github/workflows/test_pr.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Run tests - -on: - pull_request: - branches: - - main - -env: - GO_VERSION: '1.20' - -jobs: - run-tests: - runs-on: ubuntu-latest - - steps: - - name: checkout - uses: actions/checkout@v3 - - - name: install go - uses: actions/setup-go@v3 - with: - go-version: ${{ env.GO_VERSION }} - - - name: run tests - run: make test diff --git a/.github/workflows/test_push_pr.yml b/.github/workflows/test_push_pr.yml new file mode 100644 index 0000000..610b1b6 --- /dev/null +++ b/.github/workflows/test_push_pr.yml @@ -0,0 +1,54 @@ +name: Run tests and push image + +on: + pull_request: + branches: + - main + +env: + GO_VERSION: '1.20' + REGISTRY: ghcr.io + IMAGE: ghcr.io/${{ github.repository }} + +jobs: + run-tests: + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: install go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + + - name: run tests + run: make test + + push-image: + runs-on: ubuntu-latest + needs: run-tests + permissions: + packages: write + + steps: + - name: Install make + run: sudo apt-get install -y make + + - name: Log in to the Container registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout repository + uses: actions/checkout@v3 + + - name: build + run: make release + env: + IMAGE: ${{ env.IMAGE }} + version: pr-13 + #version: ${{ github.ref_name }} diff --git a/Containerile b/Containerfile similarity index 100% rename from Containerile rename to Containerfile diff --git a/Makefile b/Makefile index 5ed012f..fe6a5a6 100644 --- a/Makefile +++ b/Makefile @@ -74,8 +74,8 @@ run: manifests generate fmt vet ## Run a controller from your host. # (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. # More info: https://docs.docker.com/develop/develop-images/build_enhancements/ .PHONY: docker-build -docker-build: test ## Build docker image with the manager. - docker build -t ${IMG} . +docker-build: ## Build docker image with the manager. + docker build -f Containerfile -t ${IMG} . .PHONY: docker-push docker-push: ## Push docker image with the manager. diff --git a/cmd/main.go b/cmd/main.go index aab97b6..2261121 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,6 +19,7 @@ package main import ( "flag" "os" + "strings" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -49,14 +50,21 @@ func init() { } func main() { - var metricsAddr string - var enableLeaderElection bool - var probeAddr string + var ( + metricsAddr string + enableLeaderElection bool + probeAddr string + watchNamespaces string + ) + flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") + flag.StringVar(&watchNamespaces, "watch-namespaces", "", + "The namespaces to watch, comma-separated. Default: watch all namespaces") + opts := zap.Options{ Development: true, } @@ -81,6 +89,9 @@ func main() { if err = (&controllers.AwsAuthMapSnippetReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), + Options: controllers.AwsAuthMapSnippetReconcilerOptions{ + Namespaces: strings.Split(watchNamespaces, ","), + }, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AwsAuthMapSnippet") os.Exit(1) diff --git a/pkg/controllers/awsauthmapsnippet_controller.go b/pkg/controllers/awsauthmapsnippet_controller.go index e8dc901..3b49cb6 100644 --- a/pkg/controllers/awsauthmapsnippet_controller.go +++ b/pkg/controllers/awsauthmapsnippet_controller.go @@ -27,12 +27,21 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" crdv1beta1 "github.com/inovex/aws-auth-controller/pkg/api/v1beta1" + "github.com/inovex/aws-auth-controller/pkg/predicates" ) +// AwsAuthMapSnippetReconcilerOptions holds options for +// AwsAuthMapSnippetReconciler +type AwsAuthMapSnippetReconcilerOptions struct { + Namespaces []string +} + // AwsAuthMapSnippetReconciler reconciles an AwsAuthMapSnippet object type AwsAuthMapSnippetReconciler struct { client.Client Scheme *runtime.Scheme + + Options AwsAuthMapSnippetReconcilerOptions } const FINALIZER_NAME = "awsauth.io/finalizer" @@ -218,6 +227,7 @@ func (r *AwsAuthMapSnippetReconciler) CleanUpConfigMap(ctx context.Context, snip func (r *AwsAuthMapSnippetReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&crdv1beta1.AwsAuthMapSnippet{}). + WithEventFilter(predicates.NamespaceFilter(r.Options.Namespaces)). Complete(r) } diff --git a/pkg/predicates/predicates.go b/pkg/predicates/predicates.go new file mode 100644 index 0000000..59ac9fc --- /dev/null +++ b/pkg/predicates/predicates.go @@ -0,0 +1,22 @@ +package predicates + +import ( + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +func NamespaceFilter(namespaces []string) predicate.Predicate { + return predicate.NewPredicateFuncs(func(object client.Object) bool { + // No filter specified + if len(namespaces) == 0 || len(namespaces) == 1 && namespaces[0] == "" { + return true + } + + for _, ns := range namespaces { + if ns == object.GetNamespace() { + return true + } + } + return false + }) +} diff --git a/pkg/predicates/predicates_test.go b/pkg/predicates/predicates_test.go new file mode 100644 index 0000000..2d9be9c --- /dev/null +++ b/pkg/predicates/predicates_test.go @@ -0,0 +1,44 @@ +package predicates + +import ( + "testing" + + crdv1beta1 "github.com/inovex/aws-auth-controller/pkg/api/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/event" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +func TestPredicates(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Predicates Suite") +} + +var _ = Context("Predicates", func() { + Describe("namespaceFilter", func() { + DescribeTable("filter for namespaces", func(namespace string, watched []string, result bool) { + obj := &crdv1beta1.AwsAuthMapSnippet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-bar", + Namespace: namespace, + }, + } + pred := NamespaceFilter(watched) + Expect(pred.Create(event.CreateEvent{Object: obj})).To(Equal(result)) + }, + Entry("with no filter", "anyns", []string{}, true), + Entry("with empty filter", "anyns", []string{""}, true), + Entry("with single filter", "myns", []string{"myns"}, true), + Entry("with single filter skipped", "anyns", []string{"myns"}, false), + Entry("with multiple filter", "myns", []string{"myns", "otherns"}, true), + Entry("with multple filter skipped", "anyns", []string{"myns", "otherns"}, false), + ) + }) +})