Skip to content

feat: enable controlled CR reconciliation#6243

Merged
xiaoweim merged 12 commits into
GoogleCloudPlatform:masterfrom
xiaoweim:partial-crd
Apr 3, 2026
Merged

feat: enable controlled CR reconciliation#6243
xiaoweim merged 12 commits into
GoogleCloudPlatform:masterfrom
xiaoweim:partial-crd

Conversation

@xiaoweim

@xiaoweim xiaoweim commented Jan 22, 2026

Copy link
Copy Markdown
Collaborator

BRIEF Change description

Implement Resource Config to allow unmanaging specific resources by the Config Connector controller.

WHY do we need this change?

This feature allows users and platform administrators to selectively disable the reconciliation of specific resources (Group/Kind).

  • In Cluster Mode, resources can be unmanaged globally via the ConfigConnector object.
  • In Namespace Mode, resources can be disabled per-namespace via the
    ConfigConnectorContext object. This takes precedence over global ConfigConnector settings.

This is useful for:

  • Disabling creating controllers for unused resources to save memory.

Special notes for your reviewer:

  • Logic is implemented in pkg/controller/registration/registration_controller.go to check isResourceDisabled before starting a controller.
  • ScopedNamespace was added to kccmanager configuration to allow namespace-scoped managers to identify and prioritize their relevant ConfigConnectorContext. The controller evaluates both ConfigConnector and ConfigConnectorContext to determine if a resource should be excluded, prioritizing
    ConfigConnectorContext.
  • The feature supports unmanaging resources only. enabled: true entries are ignored and logged as warnings.
  • A new integration test TestResourceExclusion in pkg/controller/kccmanager/kccmanager_exclusion_test.go verifies end-to-end behavior for both cluster and namespace modes.

Since registration only happens at manager startup, when we update the CCC/CC, we need to restart the pod to pick up the change.

Does this PR add something which needs to be 'release noted'?

Add support for unamanging specific resources via `resourceSettings` in `ConfigConnector` (global) and `ConfigConnectorContext` (per-namespace).
  • Reviewer reviewed release note.

Additional documentation e.g., references, usage docs, etc.:


Intended Milestone

Please indicate the intended milestone.

  • Reviewer tagged PR with the actual milestone.

Tests you have done

Testing Performed

Successfully built and deployed KCC to a GKE test cluster (test-partial-crd) in Namespaced mode. Conducted manual verification of the new ResourceSettings conflict and inclusion/exclusion logic:

1. Mixed Modes Conflict Rejection

Configured a global ConfigConnector in Exclusive Mode (enabled: false), against a local ConfigConnectorContext in Inclusive Mode (enabled: true).

kubectl apply -f - <<EOF
apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnector
metadata:
  name: configconnector.core.cnrm.cloud.google.com
spec:
  mode: namespaced
  experiments:
    resourceSettings:
      enabled: false
      resources:
      - group: "pubsub.cnrm.cloud.google.com"
        kind: "PubSubTopic"
---
apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnectorContext
metadata:
  name: configconnectorcontext.core.cnrm.cloud.google.com
  namespace: test1
spec:
  googleServiceAccount: "test-kcc@xiaoweim-gke-dev.iam.gserviceaccount.com"
  experiments:
    resourceSettings:
      enabled: true
      resources:
      - group: "storage.cnrm.cloud.google.com"
        kind: "StorageBucket"
EOF

Result: The Operator correctly flags the conflict as an error and aggressively blocks the StatefulSet creation for that namespace.

$ kubectl get configconnectorcontext -n test1 -o yaml
...
  status:
    errors:
    - 'error during reconciliation: conflict: ConfigConnector and ConfigConnectorContext
      cannot mix inclusive (enabled: true) and exclusive (enabled: false) modes'
    healthy: false

$ kubectl get statefulset -n cnrm-system
NAME                      READY   AGE
cnrm-deletiondefender     1/1     2m43s
cnrm-unmanaged-detector   1/1     2m43s
# (No cnrm-controller-manager deployed)

2. Exclusion List Verification (Deny-list)

Resolved the conflict by setting both to Exclusive Mode (enabled: false).

kubectl apply -f - <<EOF
apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnectorContext
metadata:
  name: configconnectorcontext.core.cnrm.cloud.google.com
  namespace: test1
spec:
  googleServiceAccount: "test-kcc@xiaoweim-gke-dev.iam.gserviceaccount.com"
  experiments:
    resourceSettings:
      enabled: false
      resources:
      - group: "storage.cnrm.cloud.google.com"
        kind: "StorageBucket"
EOF

Result: The Operator clears the error and deploys the manager. Verified the StorageBucket and PubSubTopic controllers are aggressively excluded from memory logs:

$ kubectl get pods -n cnrm-system
NAME                                        READY   STATUS    RESTARTS   AGE
cnrm-controller-manager-44kdpwa-0           2/2     Running   0          9s

$ kubectl logs -l cnrm.cloud.google.com/component=cnrm-controller-manager -n cnrm-system -c manager | grep "Skipping controller registration"
{"severity":"info","timestamp":"2026-03-17T22:21:41.953Z","msg":"Skipping controller registration because resource is disabled in ConfigConnector or ConfigConnectorContext","group":"storage.cnrm.cloud.google.com","version":"v1beta1","kind":"StorageBucket"}
{"severity":"info","timestamp":"2026-03-17T22:21:41.954Z","msg":"Skipping controller registration because resource is disabled in ConfigConnector or ConfigConnectorContext","group":"pubsub.cnrm.cloud.google.com","version":"v1beta1","kind":"PubSubTopic"}

$ kubectl logs -l cnrm.cloud.google.com/component=cnrm-controller-manager -n cnrm-system -c manager | grep "Starting Controller" | wc -l
174

3. Inclusion List Verification (Allow-list)

Inverted configurations to an Inclusive Mode (enabled: true) across both the ConfigConnector and ConfigConnectorContext.

kubectl apply -f - <<EOF
apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnector
metadata:
  name: configconnector.core.cnrm.cloud.google.com
spec:
  mode: namespaced
  experiments:
    resourceSettings:
      enabled: true
      resources:
      - group: "pubsub.cnrm.cloud.google.com"
        kind: "PubSubTopic"
---
apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnectorContext
metadata:
  name: configconnectorcontext.core.cnrm.cloud.google.com
  namespace: test1
spec:
  googleServiceAccount: "test-kcc@xiaoweim-gke-dev.iam.gserviceaccount.com"
  experiments:
    resourceSettings:
      enabled: true
      resources:
      - group: "storage.cnrm.cloud.google.com"
        kind: "StorageBucket"
EOF

Result: Forced a pod restart to evaluate the new environment. The Pod cleanly abandons the other 170+ parent controllers, radically pruning the controller process loop to explicitly map only the whitelist elements into memory.

$ kubectl delete pod cnrm-controller-manager-44kdpwa-0 -n cnrm-system
pod "cnrm-controller-manager-44kdpwa-0" deleted

$ kubectl logs -l cnrm.cloud.google.com/component=cnrm-controller-manager -n cnrm-system -c manager | grep "Starting Controller"
{"severity":"info","timestamp":"2026-03-17T22:28:11.953Z","msg":"Starting Controller","controller":"storagebucket-parent-controller","controllerGroup":"storage.cnrm.cloud.google.com","controllerKind":"StorageBucket"}
{"severity":"info","timestamp":"2026-03-17T22:28:11.954Z","msg":"Starting Controller","controller":"pubsubtopic-parent-controller","controllerGroup":"pubsub.cnrm.cloud.google.com","controllerKind":"PubSubTopic"}

$ kubectl logs -l cnrm.cloud.google.com/component=cnrm-controller-manager -n cnrm-system -c manager | grep "Skipping controller registration" | wc -l
174
  • Run make ready-pr to ensure this PR is ready for review.
  • Perform necessary E2E testing for changed resources.

@justinsb

Copy link
Copy Markdown
Collaborator

ScopedNamespace was added to kccmanager configuration to ensure namespace-scoped managers only look at their relevant ConfigConnectorContext.

I'm not sure about this. If both ConfigConnector and ConfigConnectorContext support resourceSettings, then I would expect that both would be honored, rather than ignoring one or the other. My assumption would be that we would look first at the CCC (when in namespace mode), and then at the CC.

Am I missing a reason to ignore the CC in namespace mode?

@xiaoweim

Copy link
Copy Markdown
Collaborator Author

ScopedNamespace was added to kccmanager configuration to ensure namespace-scoped managers only look at their relevant ConfigConnectorContext.

I'm not sure about this. If both ConfigConnector and ConfigConnectorContext support resourceSettings, then I would expect that both would be honored, rather than ignoring one or the other. My assumption would be that we would look first at the CCC (when in namespace mode), and then at the CC.

Am I missing a reason to ignore the CC in namespace mode?

Yes, that is the intended behavior I want to implement My assumption would be that we would look first at the CCC (when in namespace mode), and then at the CC. I am have not pushed the code changes for that yet 🤣

@xiaoweim xiaoweim force-pushed the partial-crd branch 2 times, most recently from a0e8c37 to 122eb05 Compare January 23, 2026 00:02
@xiaoweim xiaoweim marked this pull request as ready for review January 23, 2026 00:17
}

func getResourceSetting(settings []operatorv1beta1.ResourceSetting, gvk schema.GroupVersionKind) (found bool, enabled bool) {
for _, s := range settings {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per @acpana 's suggestion, we could make resourceSetting a map of [schema.gk]properties, and we could keep adding more resource specific configuration values to the properties struct, just make sure that they are mutually exclusive with enabled:false. This also helps with efficiency as we do not need to iterate through the list here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xiaoweim

Copy link
Copy Markdown
Collaborator Author

/assign @cheftako @justinsb

@xiaoweim xiaoweim modified the milestones: 1.145, 1.146 Feb 17, 2026
@xiaoweim xiaoweim modified the milestones: 1.146, 1.147 Mar 3, 2026
@xiaoweim xiaoweim force-pushed the partial-crd branch 2 times, most recently from fef42a4 to 12a9112 Compare March 12, 2026 21:54
@xiaoweim

Copy link
Copy Markdown
Collaborator Author

ScopedNamespace was added to kccmanager configuration to ensure namespace-scoped managers only look at their relevant ConfigConnectorContext.

I'm not sure about this. If both ConfigConnector and ConfigConnectorContext support resourceSettings, then I would expect that both would be honored, rather than ignoring one or the other. My assumption would be that we would look first at the CCC (when in namespace mode), and then at the CC.

Am I missing a reason to ignore the CC in namespace mode?

No I agree, I have updated the implementation to honor both CC and CCC. with CCC taking precedence in namespace mode.

@xiaoweim xiaoweim force-pushed the partial-crd branch 4 times, most recently from 9d26e5b to 586dd3f Compare March 18, 2026 17:39
@xiaoweim

Copy link
Copy Markdown
Collaborator Author

/assign @cheftako

type ResourceFilter struct {
// Group is the API group of the resource.
// +required
Group string `json:"group"`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be a pointer in case we ever want to make it optional. I believe we have been making the use of pointer to native the standard in our types.go files recently.


// Kind is the Kind of the resource.
// +optional
Kind string `json:"kind,omitempty"`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto


type ResourceSettings struct {
// Mode controls whether the resources are included or excluded.
// Defaults to "exclude" (Exclusion mode).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should indicate all allowed values as well as the default.

@cheftako cheftako added this pull request to the merge queue Apr 3, 2026
@google-oss-prow google-oss-prow Bot added the lgtm label Apr 3, 2026
@google-oss-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: cheftako

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 3, 2026
@xiaoweim xiaoweim added this pull request to the merge queue Apr 3, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 3, 2026
@xiaoweim xiaoweim added this pull request to the merge queue Apr 3, 2026
Merged via the queue into GoogleCloudPlatform:master with commit 6b3ff9b Apr 3, 2026
166 checks passed
github-merge-queue Bot pushed a commit that referenced this pull request Apr 7, 2026
This PR fixes a bug in the ResourceSettings mode conflict logic
introduced in #6243.
The previous logic would log a warning and skip the conflict check if
both
ConfigConnector and ConfigConnectorContext were present but had
different modes.
This caused TestResourceExclusion/ConflictMode to fail as it expected an
error.

This PR ensures that the conflict check is performed first if both
settings are present.

Fixes #7325

Generated by Overseer (powered by the gemini-3-flash-preview model).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants