Skip to content

Commit

Permalink
owner reference for rbac (#276)
Browse files Browse the repository at this point in the history
  • Loading branch information
bakito authored Dec 29, 2022
1 parent bb5287e commit 44849c8
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 102 deletions.
17 changes: 14 additions & 3 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,25 @@ jobs:
- name: Install helm chart
run: |
./testdata/e2e/installChart.sh
kubectl create ns e2e-test
- name: Start 'old' eventlogger pod
run: |
kubectl apply -f testdata/e2e/old-eventlogger-pod.yaml
kubectl wait --namespace e2e-test --for=condition=ready pod event-logger-example-eventlogger-old-version --timeout=90s
- name: Setup an EventLogger
run: |
kubectl apply -f testdata/e2e/test-eventlogger.yaml
kubectl wait --namespace e2e-test \
--for=condition=ready pod \
--selector=app=event-logger-example-eventlogger \
--selector=app.kubernetes.io/component=event-logger-example-eventlogger \
--timeout=90s
- name: Check 'old' eventlogger pod is deleted
run: |
test $(kubectl get pod event-logger-example-eventlogger-old-version --no-headers | wc -l) -eq 0
- name: Start/Stop test pod
run: |
kubectl apply -f testdata/e2e/test-pod.yaml
Expand All @@ -41,11 +51,12 @@ jobs:
- name: Check logs
run: |
kubectl logs -n e2e-test -l app=event-logger-example-eventlogger | grep '"logger":"event"'
kubectl logs -n e2e-test -l app.kubernetes.io/component=event-logger-example-eventlogger | grep '"logger":"event"'
- name: Print logs
timeout-minutes: 2
run: |
echo 'Pod logs' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
kubectl logs -n e2e-test -l app=event-logger-example-eventlogger >> $GITHUB_STEP_SUMMARY
kubectl logs -n e2e-test -l app.kubernetes.io/component=event-logger-example-eventlogger >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ bin

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.out.tmp

# Kubernetes Generated files - skip generated files, except for vendored files

Expand Down
8 changes: 5 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ lint-helm:
helm lint helm/ --set webhook.enabled=true --set webhook.certManager.enabled=true

## toolbox - start
## Current working directory
LOCALDIR ?= $(shell which cygpath > /dev/null 2>&1 && cygpath -m $$(pwd) || pwd)
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
LOCALBIN ?= $(LOCALDIR)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)

Expand All @@ -87,7 +89,7 @@ CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
SEMVER_VERSION ?= v1.1.3
MOCKGEN_VERSION ?= v1.6.0
GOLANGCI_LINT_VERSION ?= v1.50.1
GORELEASER_VERSION ?= v1.13.1
GORELEASER_VERSION ?= v1.14.0
HELM_DOCS_VERSION ?= v1.11.0
CONTROLLER_GEN_VERSION ?= v0.11.1

Expand Down Expand Up @@ -127,7 +129,7 @@ update-toolbox-tools:
$(LOCALBIN)/goreleaser \
$(LOCALBIN)/helm-docs \
$(LOCALBIN)/controller-gen
toolbox makefile -f $$(pwd)/Makefile \
toolbox makefile -f $(LOCALDIR)/Makefile \
github.com/bakito/semver \
github.com/golang/mock/mockgen \
github.com/golangci/golangci-lint/cmd/golangci-lint \
Expand Down
6 changes: 2 additions & 4 deletions controllers/setup/eventlogger_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

Expand Down Expand Up @@ -63,8 +62,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
return r.updateCR(ctx, cr, reqLogger, err)
}

reqLogger.Info("Reconciling event logger")

if err = cr.Spec.Validate(); err != nil {
return r.updateCR(ctx, cr, reqLogger, err)
}
Expand All @@ -78,7 +75,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
pod := r.podForCR(cr)

// set owner reference for pod
if err := controllerutil.SetOwnerReference(cr, pod, r.Scheme); err != nil {
if err := ctrl.SetControllerReference(cr, pod, r.Scheme); err != nil {
return r.updateCR(ctx, cr, reqLogger, err)
}

Expand All @@ -89,6 +86,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
}

if cr.HasChanged() || saccChanged || roleChanged || rbChanged || podChanged {
reqLogger.Info("Reconciling event logger")
return r.updateCR(ctx, cr, reqLogger, nil)
}

Expand Down
62 changes: 45 additions & 17 deletions controllers/setup/eventlogger_controller_pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,34 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

const (
labelComponent = "app.kubernetes.io/component"
labelManagedBy = "app.kubernetes.io/managed-by"
)

func (r *Reconciler) createOrReplacePod(ctx context.Context, cr *eventloggerv1.EventLogger, pod *corev1.Pod,
reqLogger logr.Logger) (bool, error,
) {
podList := &corev1.PodList{}
opts := []client.ListOption{
client.InNamespace(cr.Namespace),
client.MatchingLabels(map[string]string{
"app": loggerName(cr),
"created-by": "eventlogger",
}),
}
err := r.List(ctx, podList, opts...)
// current labels
labels := make(map[string]string)
applyDefaultLabels(cr, labels)
podList, err := r.findPods(ctx, cr, labels)
if err != nil {
return false, err
}

if len(podList.Items) == 0 {
// old labels
oldPods, err := r.findPods(ctx, cr, map[string]string{
"app": loggerName(cr),
"created-by": "eventlogger",
})
if err != nil {
return false, err
}
podList.Items = oldPods.Items
}

replacePod := false
if len(podList.Items) == 1 {
op := podList.Items[0]
Expand Down Expand Up @@ -81,6 +93,15 @@ func (r *Reconciler) createOrReplacePod(ctx context.Context, cr *eventloggerv1.E
return false, nil
}

func (r *Reconciler) findPods(ctx context.Context, cr *eventloggerv1.EventLogger, matchLabels map[string]string) (*corev1.PodList, error) {
podList := &corev1.PodList{}
opts := []client.ListOption{
client.InNamespace(cr.Namespace),
client.MatchingLabels(matchLabels),
}
return podList, r.List(ctx, podList, opts...)
}

// podForCR returns a pod with the same name/namespace as the cr
func (r *Reconciler) podForCR(cr *eventloggerv1.EventLogger) *corev1.Pod {
metricsAddrFlag := flag.Lookup(cnst.ArgMetricsAddr)
Expand All @@ -93,13 +114,6 @@ func (r *Reconciler) podForCR(cr *eventloggerv1.EventLogger) *corev1.Pod {
}
metricsPort := metricsAddr[:1]

labels := make(map[string]string)
for k, v := range cr.Spec.Labels {
labels[k] = v
}
labels["app"] = loggerName(cr)
labels["created-by"] = "eventlogger"

annotations := make(map[string]string)
for k, v := range cr.Spec.Annotations {
annotations[k] = v
Expand Down Expand Up @@ -145,7 +159,7 @@ func (r *Reconciler) podForCR(cr *eventloggerv1.EventLogger) *corev1.Pod {
ObjectMeta: metav1.ObjectMeta{
GenerateName: loggerName(cr) + "-",
Namespace: cr.Namespace,
Labels: labels,
Labels: copyLabels(cr),
Annotations: annotations,
},
Spec: corev1.PodSpec{
Expand All @@ -159,3 +173,17 @@ func (r *Reconciler) podForCR(cr *eventloggerv1.EventLogger) *corev1.Pod {

return pod
}

func copyLabels(cr *eventloggerv1.EventLogger) map[string]string {
labels := make(map[string]string)
for k, v := range cr.Spec.Labels {
labels[k] = v
}
applyDefaultLabels(cr, labels)
return labels
}

func applyDefaultLabels(cr *eventloggerv1.EventLogger, labels map[string]string) {
labels[labelComponent] = loggerName(cr)
labels[labelManagedBy] = "eventlogger"
}
96 changes: 50 additions & 46 deletions controllers/setup/eventlogger_controller_rbac.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

Expand All @@ -31,60 +32,17 @@ func (r *Reconciler) setupRbac(ctx context.Context, cr *eventloggerv1.EventLogge
sacc, role, rb := rbacForCR(cr)

if cr.Spec.ServiceAccount == "" {
saccRes, err := controllerutil.CreateOrUpdate(ctx, r.Client, sacc, func() error {
if sacc.Labels == nil {
sacc.Labels = map[string]string{}
}
sacc.Labels["app"] = loggerName(cr)
return nil
})
saccRes, err := controllerutil.CreateOrUpdate(ctx, r.Client, sacc, r.mutateServiceAccount(sacc, cr))
if err != nil {
return false, false, false, err
}

roleRes, err := controllerutil.CreateOrUpdate(ctx, r.Client, role, func() error {
if role.Labels == nil {
role.Labels = map[string]string{}
}
role.Labels["app"] = loggerName(cr)
role.Rules = []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"events", "pods"},
Verbs: []string{"watch", "get", "list"},
},
{
APIGroups: []string{"eventlogger.bakito.ch"},
Resources: []string{"eventloggers"},
Verbs: []string{"get", "list", "patch", "update", "watch"},
},
}
return nil
})
roleRes, err := controllerutil.CreateOrUpdate(ctx, r.Client, role, r.mutateRole(role, cr))
if err != nil {
return false, false, false, err
}

rbRes, err := controllerutil.CreateOrUpdate(ctx, r.Client, rb, func() error {
if rb.Labels == nil {
rb.Labels = map[string]string{}
}
rb.Labels["app"] = loggerName(cr)

rb.Subjects = []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: loggerName(cr),
Namespace: cr.Namespace,
},
}
rb.RoleRef = rbacv1.RoleRef{
Kind: "Role",
APIGroup: "rbac.authorization.k8s.io",
Name: loggerName(cr),
}
return nil
})
rbRes, err := controllerutil.CreateOrUpdate(ctx, r.Client, rb, r.mutateRolebinding(rb, cr))
if err != nil {
return false, false, false, err
}
Expand All @@ -109,6 +67,52 @@ func (r *Reconciler) setupRbac(ctx context.Context, cr *eventloggerv1.EventLogge
return false, false, false, nil
}

func (r *Reconciler) mutateServiceAccount(sacc *corev1.ServiceAccount, cr *eventloggerv1.EventLogger) func() error {
return func() error {
sacc.Labels = copyLabels(cr)
return ctrl.SetControllerReference(cr, sacc, r.Scheme)
}
}

func (r *Reconciler) mutateRole(role *rbacv1.Role, cr *eventloggerv1.EventLogger) func() error {
return func() error {
role.Labels = copyLabels(cr)
role.Rules = []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"events", "pods"},
Verbs: []string{"watch", "get", "list"},
},
{
APIGroups: []string{"eventlogger.bakito.ch"},
Resources: []string{"eventloggers"},
Verbs: []string{"get", "list", "patch", "update", "watch"},
},
}
return ctrl.SetControllerReference(cr, role, r.Scheme)
}
}

func (r *Reconciler) mutateRolebinding(rb *rbacv1.RoleBinding, cr *eventloggerv1.EventLogger) func() error {
return func() error {
rb.Labels = copyLabels(cr)

rb.Subjects = []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: loggerName(cr),
Namespace: cr.Namespace,
},
}
rb.RoleRef = rbacv1.RoleRef{
Kind: "Role",
APIGroup: "rbac.authorization.k8s.io",
Name: loggerName(cr),
}
return ctrl.SetControllerReference(cr, rb, r.Scheme)
}
}

func rbacForCR(cr *eventloggerv1.EventLogger) (*corev1.ServiceAccount, *rbacv1.Role, *rbacv1.RoleBinding) {
sacc := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Expand Down
Loading

0 comments on commit 44849c8

Please sign in to comment.