Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce accesses caching #46

Merged
merged 5 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fmt: ## Run go fmt against code.

.PHONY: test
test: ## Run go test against code.
$(GINKGO) --label-filter='!perf'
$(GINKGO) --label-filter='!perf' ./pkg/... ./

.PHONY: test-perf
test-perf: ## Run performance tests
Expand All @@ -61,6 +61,7 @@ test-perf: ## Run performance tests
--name namespace-lister-perf-test $(PERF_CLUSTER_PROVIDER_FLAGS)
KUBECONFIG=$(PERF_CLUSTER_KUBECONFIG) $(GINKGO) --label-filter='perf' \
--keep-going --procs=1 --flake-attempts 2 --output-dir=$(PERF_OUT_DIR)
# -$(PERF_CLUSTER_PROVIDER) delete cluster --name namespace-lister-perf-test

.PHONY: image-build
image-build:
Expand Down
5 changes: 5 additions & 0 deletions acceptance/config/patches/with_cache_resyncperiod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: CACHE_RESYNC_PERIOD
value: '20s'
74 changes: 42 additions & 32 deletions acceptance/pkg/suite/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@ package suite
import (
"context"
"fmt"
"log"
"slices"
"time"

"github.com/cucumber/godog"

corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"

tcontext "github.com/konflux-ci/namespace-lister/acceptance/pkg/context"
arest "github.com/konflux-ci/namespace-lister/acceptance/pkg/rest"
)

func InjectSteps(ctx *godog.ScenarioContext) {
//read
// read
ctx.Step(`^ServiceAccount has access to a namespace$`,
func(ctx context.Context) (context.Context, error) { return UserInfoHasAccessToNNamespaces(ctx, 1) })
ctx.Step(`^User has access to a namespace$`,
Expand Down Expand Up @@ -92,49 +95,56 @@ func TheUserCanRetrieveOnlyTheNamespacesTheyHaveAccessTo(ctx context.Context) (c
return ctx, err
}

ann := corev1.NamespaceList{}
if err := cli.List(ctx, &ann); err != nil {
return ctx, err
}

enn := tcontext.Namespaces(ctx)
if expected, actual := len(enn), len(ann.Items); expected != actual {
return ctx, fmt.Errorf("expected %d namespaces, actual %d", expected, actual)
}
return ctx, wait.PollUntilContextTimeout(ctx, 2*time.Second, 1*time.Minute, true, func(ctx context.Context) (done bool, err error) {
ann := corev1.NamespaceList{}
if err := cli.List(ctx, &ann); err != nil {
log.Printf("error listing namespaces: %v", err)
return false, nil
}

for _, en := range enn {
if !slices.ContainsFunc(ann.Items, func(an corev1.Namespace) bool {
return en.Name == an.Name
}) {
return ctx, fmt.Errorf("expected namespace %s not found in actual namespace list: %v", en.Name, ann.Items)
enn := tcontext.Namespaces(ctx)
if expected, actual := len(enn), len(ann.Items); expected != actual {
log.Printf("expected %d namespaces, actual %d", expected, actual)
return false, nil
}
}

return ctx, nil
for _, en := range enn {
if !slices.ContainsFunc(ann.Items, func(an corev1.Namespace) bool {
return en.Name == an.Name
}) {
log.Printf("expected namespace %s not found in actual namespace list: %v", en.Name, ann.Items)
return false, nil
}
}
return true, nil
})
}

func TheUserCanRetrieveTheNamespace(ctx context.Context) (context.Context, error) {
run := tcontext.RunId(ctx)

cli, err := tcontext.InvokeBuildUserClientFunc(ctx)
if err != nil {
return ctx, err
}

n := corev1.Namespace{}
k := types.NamespacedName{Name: fmt.Sprintf("run-%s-0", run)}
if err := cli.Get(ctx, k, &n); err != nil {
return ctx, err
}

enn := tcontext.Namespaces(ctx)
if expected, actual := 1, len(enn); expected != actual {
return ctx, fmt.Errorf("expected %d namespaces, actual %d: %v", expected, actual, enn)
}
return ctx, wait.PollUntilContextTimeout(ctx, 2*time.Second, 1*time.Minute, true, func(ctx context.Context) (done bool, err error) {
n := corev1.Namespace{}
k := types.NamespacedName{Name: fmt.Sprintf("run-%s-0", run)}
if err := cli.Get(ctx, k, &n); err != nil {
log.Printf("error getting namespace %v: %v", k, err)
return false, nil
}

if expected, actual := n.Name, enn[0].Name; actual != expected {
return ctx, fmt.Errorf("expected namespace %s, actual %s", expected, actual)
}
enn := tcontext.Namespaces(ctx)
if expected, actual := 1, len(enn); expected != actual {
log.Printf("expected %d namespaces, actual %d: %v", expected, actual, enn)
return false, nil
}

return ctx, nil
if expected, actual := n.Name, enn[0].Name; actual != expected {
log.Printf("expected namespace %s, actual %s", expected, actual)
return false, nil
}
return true, nil
})
}
14 changes: 14 additions & 0 deletions acceptance/test/dumb-proxy/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ deploy-namespace-lister: $(OUT_DIR)
--kind "Deployment" \
--name "namespace-lister" \
--version "v1" && \
cp "$(ROOT_DIR)/../config/patches/with_log_debug.yaml" . && \
kustomize edit add patch \
--path "with_log_debug.yaml" \
--group "apps" \
--kind "Deployment" \
--name "namespace-lister" \
--version "v1" && \
cp "$(ROOT_DIR)/config/patches/with_cache_resyncperiod.yaml" . && \
kustomize edit add patch \
--path "with_cache_resyncperiod.yaml" \
--group "apps" \
--kind "Deployment" \
--name "namespace-lister" \
--version "v1" && \
kustomize build | $(KUBECTL) apply -f - ; \
)

Expand Down
18 changes: 16 additions & 2 deletions acceptance/test/smart-proxy/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ deploy-namespace-lister: $(OUT_DIR)
cd $(OUT_DIR)/config && \
kustomize init && \
kustomize edit add base "../../../../../config" && \
kustomize edit set namespace namespace-lister && \
kustomize edit set image "namespace-lister:latest=$(IMG)" && \
cp "$(ROOT_DIR)/../config/patches/with_header_auth.yaml" . && \
kustomize edit add patch \
--path "with_header_auth.yaml" \
Expand All @@ -40,8 +42,20 @@ deploy-namespace-lister: $(OUT_DIR)
--kind "Deployment" \
--name "namespace-lister" \
--version "v1" && \
kustomize edit set namespace namespace-lister && \
kustomize edit set image "namespace-lister:latest=$(IMG)" && \
cp "$(ROOT_DIR)/../config/patches/with_log_debug.yaml" . && \
kustomize edit add patch \
--path "with_log_debug.yaml" \
--group "apps" \
--kind "Deployment" \
--name "namespace-lister" \
--version "v1" && \
cp "$(ROOT_DIR)/config/patches/with_cache_resyncperiod.yaml" . && \
kustomize edit add patch \
--path "with_cache_resyncperiod.yaml" \
--group "apps" \
--kind "Deployment" \
--name "namespace-lister" \
--version "v1" && \
kustomize build | $(KUBECTL) apply -f - ; \
)

Expand Down
72 changes: 72 additions & 0 deletions access_cache_startup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package main

import (
"context"
"os"
"time"

authcache "github.com/konflux-ci/namespace-lister/pkg/auth/cache"

corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
toolscache "k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac"
crcache "sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func buildAndStartAccessCache(ctx context.Context, resourceCache crcache.Cache) (*authcache.SynchronizedAccessCache, error) {
aur := &CRAuthRetriever{resourceCache, ctx, getLoggerFromContext(ctx)}
sae := rbac.NewSubjectAccessEvaluator(aur, aur, aur, aur, "")
synchCache := authcache.NewSynchronizedAccessCache(
sae,
resourceCache, authcache.CacheSynchronizerOptions{
Logger: getLoggerFromContext(ctx),
ResyncPeriod: getResyncPeriodFromEnvOrZero(ctx),
},
)

// register event handlers on resource cache
oo := []client.Object{
&corev1.Namespace{},
&rbacv1.RoleBinding{},
&rbacv1.ClusterRole{},
&rbacv1.ClusterRoleBinding{},
&rbacv1.Role{},
}
for _, o := range oo {
i, err := resourceCache.GetInformer(ctx, o)
if err != nil {
return nil, err
}

if _, err := i.AddEventHandler(
toolscache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) { synchCache.Request() },
UpdateFunc: func(oldObj, newObj interface{}) { synchCache.Request() },
DeleteFunc: func(obj interface{}) { synchCache.Request() },
}); err != nil {
return nil, err
}
}
synchCache.Start(ctx)

if err := synchCache.Synch(ctx); err != nil {
return nil, err
}
return synchCache, nil
}

func getResyncPeriodFromEnvOrZero(ctx context.Context) time.Duration {
var zero time.Duration
rps, ok := os.LookupEnv(EnvCacheResyncPeriod)
if !ok {
return zero
}
rp, err := time.ParseDuration(rps)
if err != nil {
getLoggerFromContext(ctx).Warn("can not parse duration from environment variable", "error", err)
return zero
}
return rp
}
5 changes: 5 additions & 0 deletions config/patches/with_cache_resyncperiod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: CACHE_RESYNC_PERIOD
value: '10m'
5 changes: 5 additions & 0 deletions config/patches/with_log_debug.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- op: replace
path: /spec/template/spec/containers/0/env/0
value:
name: LOG_LEVEL
value: "-4"
7 changes: 4 additions & 3 deletions const.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package main

const (
EnvLogLevel string = "LOG_LEVEL"
EnvUsernameHeader string = "AUTH_USERNAME_HEADER"
EnvAddress string = "ADDRESS"
EnvLogLevel string = "LOG_LEVEL"
EnvUsernameHeader string = "AUTH_USERNAME_HEADER"
EnvAddress string = "ADDRESS"
EnvCacheResyncPeriod string = "CACHE_RESYNC_PERIOD"

DefaultAddr string = ":8080"
DefaultHeaderUsername string = "X-Email"
Expand Down
7 changes: 7 additions & 0 deletions interfaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@ package main_test

import (
"k8s.io/client-go/rest"

namespacelister "github.com/konflux-ci/namespace-lister"
)

//go:generate mockgen -source=interfaces_test.go -destination=mocks/rest_interface.go -package=mocks

type FakeInterface interface {
rest.Interface
}

type FakeSubjectNamespacesLister interface {
namespacelister.SubjectNamespacesLister
}
21 changes: 13 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"syscall"

"github.com/go-logr/logr"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log"
)
Expand Down Expand Up @@ -69,20 +68,26 @@ func run(l *slog.Logger) error {

ctx = setLoggerIntoContext(ctx, l)

// create cache
l.Info("creating cache")
cacheCfg, err := NewCacheConfigFromEnv(cfg)
// create resource cache
l.Info("creating resource cache")
cacheCfg, err := NewResourceCacheConfigFromEnv(cfg)
if err != nil {
return err
}
cache, err := BuildAndStartCache(ctx, cacheCfg)
resourceCache, err := BuildAndStartResourceCache(ctx, cacheCfg)
if err != nil {
return err
}

// create access cache
l.Info("creating access cache")
accessCache, err := buildAndStartAccessCache(ctx, resourceCache)
if err != nil {
return err
}

// create the authorizer and the namespace lister
auth := NewAuthorizer(ctx, cache)
nsl := NewNamespaceLister(cache, auth)
// create the namespace lister
nsl := NewNamespaceListerForSubject(accessCache)

// build http server
l.Info("building server")
Expand Down
40 changes: 40 additions & 0 deletions mocks/rest_interface.go

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

Loading
Loading