Skip to content

Commit

Permalink
fix: Properly account for the template's namespace when creating watches
Browse files Browse the repository at this point in the history
This fixes an issue with "permission denied" being reported when the
namespace field is missing in matrix entries. The expected behavior is
that the namespace of the template resource is used when the input
object namespace is omitted.
  • Loading branch information
codablock committed Jul 19, 2024
1 parent 1564170 commit 27a0f9a
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 20 deletions.
4 changes: 2 additions & 2 deletions controllers/objecttemplate_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,11 @@ func (r *ObjectTemplateReconciler) doReconcile(ctx context.Context, rt *template
newObjects := map[templatesv1alpha1.ObjectRef]struct{}{}
for _, me := range rt.Spec.Matrix {
if me.Object != nil {
newObjects[me.Object.Ref] = struct{}{}
err = wt.addWatchForObject(ctx, me.Object.Ref)
refWithNs, err := wt.addWatchForObject(ctx, me.Object.Ref)
if err != nil {
return err
}
newObjects[refWithNs] = struct{}{}
}
}
wt.removeDeletedWatches(ctx, newObjects)
Expand Down
14 changes: 5 additions & 9 deletions controllers/texttemplate_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,29 +129,25 @@ func (r *TextTemplateReconciler) doReconcile(ctx context.Context, tt *templatesv
wt.setClient(ctx, objClient, tt.Spec.ServiceAccountName)
newObjects := map[templatesv1alpha1.ObjectRef]struct{}{}
if tt.Spec.TemplateRef != nil && tt.Spec.TemplateRef.ConfigMap != nil {
ns := tt.Spec.TemplateRef.ConfigMap.Namespace
if ns == "" {
ns = tt.Namespace
}
objRef := templatesv1alpha1.ObjectRef{
APIVersion: "v1",
Kind: "ConfigMap",
Namespace: ns,
Namespace: tt.Spec.TemplateRef.ConfigMap.Namespace,
Name: tt.Spec.TemplateRef.ConfigMap.Name,
}
err = wt.addWatchForObject(ctx, objRef)
refWithNs, err := wt.addWatchForObject(ctx, objRef)
if err != nil {
return err
}
newObjects[objRef] = struct{}{}
newObjects[refWithNs] = struct{}{}
}
for _, me := range tt.Spec.Inputs {
if me.Object != nil {
err = wt.addWatchForObject(ctx, me.Object.Ref)
refWithNs, err := wt.addWatchForObject(ctx, me.Object.Ref)
if err != nil {
return err
}
newObjects[me.Object.Ref] = struct{}{}
newObjects[refWithNs] = struct{}{}
}
}
wt.removeDeletedWatches(ctx, newObjects)
Expand Down
28 changes: 19 additions & 9 deletions controllers/watches_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"k8s.io/apimachinery/pkg/watch"
"net/http"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
Expand Down Expand Up @@ -87,24 +88,33 @@ func (wt *watchesForTemplate) setClient(ctx context.Context, objClient client.Wi
wt.client = objClient
}

func (wt *watchesForTemplate) addWatchForObject(ctx context.Context, objectRef templatesv1alpha1.ObjectRef) error {
func (wt *watchesForTemplate) addWatchForObject(ctx context.Context, objectRef templatesv1alpha1.ObjectRef) (templatesv1alpha1.ObjectRef, error) {
logger := log.FromContext(ctx)

gvk, err := objectRef.GroupVersionKind()
if err != nil {
return objectRef, err
}

// if namespace is not set, default to the template's namespace
if objectRef.Namespace == "" {
if isNs, err := apiutil.IsGVKNamespaced(gvk, wt.client.RESTMapper()); err != nil {
return objectRef, fmt.Errorf("failed to determine if object is namespaced: %w", err)
} else if isNs {
objectRef.Namespace = wt.templateKey.Namespace
}
}

wt.mutex.Lock()
defer wt.mutex.Unlock()

w := wt.watches[objectRef]
if w != nil {
return nil
return objectRef, nil
}

logger.V(1).Info("Starting watch for object", "templateKey", wt.templateKey, "objectRef", objectRef)

gvk, err := objectRef.GroupVersionKind()
if err != nil {
return err
}

// this is a single-object watch that does NOT require global watch permissions!
var dummy unstructured.UnstructuredList
dummy.SetGroupVersionKind(gvk)
Expand All @@ -120,7 +130,7 @@ func (wt *watchesForTemplate) addWatchForObject(ctx context.Context, objectRef t
err = fmt.Errorf("watch for %s \"%s\" is forbidden: %w", gvk.Kind, objectRef.Name, err)
}
}
return err
return objectRef, err
}
wt.watches[objectRef] = w

Expand All @@ -132,7 +142,7 @@ func (wt *watchesForTemplate) addWatchForObject(ctx context.Context, objectRef t
}
}()

return nil
return objectRef, nil
}

func (wt *watchesForTemplate) removeDeletedWatches(ctx context.Context, newRefs map[templatesv1alpha1.ObjectRef]struct{}) {
Expand Down

0 comments on commit 27a0f9a

Please sign in to comment.