feat(namespacesync): add NamespaceSyncController for per-namespace resource management - #3581
feat(namespacesync): add NamespaceSyncController for per-namespace resource management#3581jkhelil wants to merge 2 commits into
Conversation
c1be9cb to
c2fc182
Compare
c2fc182 to
481eaa9
Compare
a66cbfa to
ba1e9f7
Compare
|
@jkhelil - If you are still planning to pursue this PR, please rebase. |
|
@waveywaves @pratap0007 Would you mind review this please ? |
|
/assign @waveywaves |
ba1e9f7 to
903059b
Compare
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3581 +/- ##
==========================================
+ Coverage 26.44% 26.77% +0.32%
==========================================
Files 465 467 +2
Lines 24991 25016 +25
==========================================
+ Hits 6609 6698 +89
+ Misses 17661 17621 -40
+ Partials 721 697 -24
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| return err | ||
| } | ||
|
|
||
| cfg := tc.Spec.Platforms.OpenShift.NamespaceSync |
There was a problem hiding this comment.
Older TektonConfig objects will not have this field, so namespace setup may stop after upgrade. Could we handle existing configurations and add an upgrade test?
| if cfg.NamespaceSelector == nil { | ||
| return true | ||
| } | ||
| sel, err := metav1.LabelSelectorAsSelector(cfg.NamespaceSelector) |
There was a problem hiding this comment.
{} matches every namespace, not none, and invalid selectors also match every namespace. Could we fix and test both cases?
| }) | ||
|
|
||
| // Namespace Add/Update → reconcile that namespace. | ||
| if _, err := nsInf.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ |
There was a problem hiding this comment.
Deleting a namespace leaves its pipeline entry in the cluster-wide permission binding. Could we remove it on deletion?
| // To avoid a thundering-herd on clusters that don't use secret bindings, | ||
| // we only enqueue when NamespaceSync has SecretBindings configured AND the | ||
| // secret name/labels match at least one binding rule. | ||
| if _, err := secretInf.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ |
There was a problem hiding this comment.
Secret label changes are not watched. Could we handle updates so matching Secrets are added and removed?
| } | ||
| } | ||
|
|
||
| if len(cfg.SecretBindings) > 0 { |
There was a problem hiding this comment.
Changing or removing secretBindings leaves old Secret references. Could we remove references added by this controller?
| return nil | ||
| } | ||
|
|
||
| return retry.RetryOnConflict(retry.DefaultRetry, func() error { |
There was a problem hiding this comment.
Each retry uses the same outdated ServiceAccount, so it cannot resolve a conflict. Could we fetch it again on each retry?
|
|
||
| logger.Infof("Creating edit RoleBinding in namespace %s", ns.Name) | ||
| _, err = rbClient.Create(ctx, &rbacv1.RoleBinding{ | ||
| ObjectMeta: metav1.ObjectMeta{ |
There was a problem hiding this comment.
New RoleBindings have no owner, and incorrect existing bindings are not fixed. Could we preserve ownership and correct existing bindings?
Address review feedback on PR tektoncd#3581 (RFE-7814 namespace sync): - Apply TektonConfig defaulting in-memory on every reconcile so pre-existing CRs created before this feature keep syncing without requiring a spec edit. - Correct RoleBinding/OwnerReference drift instead of silently ignoring it, and always run secret binding cleanup even when secretBindings is empty. - Track secrets this controller has bound via an annotation on the pipeline SA so stale references are removed when a binding rule (or the whole secretBindings list) is changed or removed, for both named and labelSelector bindings. - Strip Secret payloads from the informer cache and watch for label changes that add/remove a Secret from a labelSelector binding. - Treat an explicit empty namespaceSelector as "match nothing" and fail malformed selectors closed. - Simplify ensureSecretBindings into smaller, single-purpose helpers. Add e2e coverage for the two scenarios PR tektoncd#3581 flagged as missing before merge: named/labelSelector secret binding lifecycle, and CRB subject cleanup on namespace deletion. Adds WaitForServiceAccountImagePullSecret and WaitForClusterRoleBindingSubject helpers to test/resources/rbac.go. Also fixes two test fixture gaps found while re-running the suite: a missing "edit" ClusterRole fixture, and a namespace-deletion test that never deleted the pipeline SA it was supposed to simulate away. Signed-off-by: Jawed khelil <jkhelil@redhat.com> Assisted-by: Claude Sonnet 5 (via Cursor)
903059b to
ca9814b
Compare
Replace the O(N) scan-based per-namespace reconciliation in rbac.go with a watch-based NamespaceSyncController that reacts to namespace, ServiceAccount, Secret, and TektonConfig events instead of re-scanning every namespace on each TektonConfig reconcile. New typed API under TektonConfig.spec.platforms.openShift.namespaceSync: - createPipelineSA: manage the pipeline SA (replaces createRbacResource) - createCABundles: manage CA bundle ConfigMaps (replaces createCABundleConfigMaps) - createEditRoleBinding: manage openshift-pipelines-edit RoleBinding (replaces legacyPipelineRbac) - createSCCRoleBinding: manage pipelines-scc-rolebinding (default true) - secretBindings: bind registry secrets (by name or label selector) to the pipeline SA - namespaceSelector: restrict sync to namespaces matching labels Signed-off-by: Jawed khelil <jkhelil@redhat.com> Assisted-by: Claude Sonnet 4.6 (via Cursor) Assisted-by: Claude Sonnet 5 (via Cursor) Co-authored-by: Cursor <cursoragent@cursor.com>
ca9814b to
7672846
Compare
SetDefaults already migrates the deprecated createRbacResource, createCABundleConfigMaps, and legacyPipelineRbac spec.params entries onto the typed spec.platforms.openshift.namespaceSync fields, but only in-memory on a deep copy on every reconcile. It never writes the result back, so upgraded CRs kept carrying the legacy params forward indefinitely with no way to tell they were deprecated. Add migrateLegacyNamespaceSyncParams, a pre-upgrade job (following the existing removeHubFromTektonConfig/removeDeprecatedDisableAffinity Assistant pattern) that persists the same migration once per upgrade, so the stored CR ends up on the typed schema and the legacy params are actually removed from spec.params. Signed-off-by: Jawed khelil <jkhelil@redhat.com> Assisted-by: Claude Sonnet 5 (via Cursor) Co-authored-by: Cursor <cursoragent@cursor.com>
…amespaceSync migration SetDefaults() already migrates createRbacResource/createCABundleConfigMaps/ legacyPipelineRbac in-memory on every reconcile, but tektoncd/operator#3581 also added a one-time pre-upgrade job that persists this migration onto the stored TektonConfig CR. Add a spec that forces that job to re-run (by resetting the pre-upgrade-version status annotation, as if the operator had just been upgraded) and asserts the legacy params are actually removed from spec.params rather than just recomputed in memory.
NamespaceSyncController E2E Test ProofResult: 15/15 specs PASSED, 0 failed, 0 errors.
Cluster under testSee
Per-spec results
Artifacts in this folder
How this was runPATH="/tmp/faux-bin:$PATH" go run github.com/onsi/ginkgo/v2/ginkgo -v \
--focus "NamespaceSyncController" \
--junit-report=nssync-junit.xml \
--json-report=nssync-report.json \
./tests/operator/...( Note: an earlier run against this same cluster caught a real test-code bug (two legacy-params specs issued the |
Changes
Introduces a new
NamespaceSyncControllerthat replaces thescan-based batch processing in
rbac.gowith an event-driven,per-namespace reconciler. Addresses RFE-7814 (flexible service
account binding for Quay Robot credentials).
What this does
NamespaceSyncController— a watch-based controller thatreacts to Namespace, ServiceAccount, Secret, and TektonConfig
events to ensure per-namespace Tekton resources are present and
up to date in every user namespace
pipelineSA, SCC RoleBinding, edit RoleBinding, andCA bundle ConfigMaps in each namespace
openshift-pipelines-clusterinterceptorsCRBincrementally (add/remove only the affected namespace's subject)
spec.platforms.openshift .namespaceSync.secretBindings(the core RFE-7814 use case)spec.platforms.openshift.namespaceSyncAPI field toTektonConfig, replacing legacy
spec.paramsentriesrbac.goLeaderAwareFuncsembedding (required by Knative sharedmain)namespaceSyncschema to the TektonConfig CRDStatus
Work in progress — more e2e tests needed before merge:
make test lintfull passVerified on cluster
All per-namespace resources (pipeline SA, SCC RoleBinding, edit
RoleBinding, CA bundles, CRB subject) created correctly in new
namespaces within seconds. Established namespaces unaffected.
Submitter Checklist
make test lintbefore submitting a PRRelease Notes
Made with Cursor