Skip to content

KUBE-154: establish MongoDBSearch lifecycle identity#1362

Draft
anandsyncs wants to merge 2 commits into
masterfrom
search-kube154-label-sweep-lifecycle
Draft

KUBE-154: establish MongoDBSearch lifecycle identity#1362
anandsyncs wants to merge 2 commits into
masterfrom
search-kube154-label-sweep-lifecycle

Conversation

@anandsyncs

@anandsyncs anandsyncs commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

This is stack 1/4 for KUBE-154. It establishes stable MongoDBSearch resource identity and safe legacy state adoption before stack 2 atomically adds label-sweep cleanup, owner-reference removal, and lifecycle watches.

The change protects the Search owner name, namespace, UID, cluster, and component labels on operator-managed resources; reapplies those labels after user metadata overrides without removing unrelated labels; and gives Search and metrics state explicit missing/matching/mismatched UID semantics. Operator-managed ingress TLS Secret copies now carry component=mongot consistently for both replica-set and sharded Search topologies.

Scope

  • stamps current Search identity on mongot StatefulSets, Services, ConfigMaps, generated TLS Secret copies, Envoy and metrics-forwarder Deployments/ConfigMaps, Search state, and metrics state
  • preserves unrelated user metadata while restoring protected labels after StatefulSet and Deployment overrides
  • applies owner name, namespace, UID, and component=mongot identity to every operator-managed ingress TLS Secret copy; legacy single-cluster copies intentionally omit the cluster label
  • adopts legacy state with no UID marker, preserves state for matching UIDs, and resets only for an explicit UID mismatch
  • stamps current identity during normal state mutation/write while preserving existing owner references
  • adds focused table-driven Go tests for label protection, managed-resource identity, replica-set and sharded generated TLS identity, and Search/metrics state adoption

Intentionally excluded

  • no owner-reference removal; master’s existing in-cluster garbage collection remains intact
  • no confirmed-absence cleanup, label sweep, UID-preconditioned deletion, stale-shard cleanup, or lifecycle watches
  • no ConfigMap/Secret delete routing, Python/e2e changes, shared e2e helpers, or committed Evergreen/upgrade wiring

Landing history

  1. e0d3deb2a100ef1dc8c6f7026f910bf481f52d61KUBE-154: establish MongoDBSearch resource identity
  2. 5aa0e085809d2d414485d122a7f789a3b6e0a265KUBE-154: adopt legacy MongoDBSearch state

Both commits are linear on master, include production changes and their focused tests together, carry the required co-author trailer, and pass their focused package tests independently. The state-adoption commit has the same stable patch ID as the previously accepted adoption commit.

Proof of Work

Local

  • each final commit independently: go test ./controllers/searchcontroller ./controllers/operator ./pkg/handler ./pkg/tls
  • cumulative make test-race: 2,849 passed, 3 existing skips
  • make fmt, gofmt, and git diff --check clean
  • fresh read-only diff review confirmed the ingress TLS correction and found no in-scope regression or rebase scope drift
  • scoped diff audit confirms no cleanup, watch, e2e, upgrade, or owner-reference-removal changes

Targeted Evergreen

Exhaustive Search matrix

Patch 6a5a08a157cb640007c484b4 ran exactly 56 requested targets (55 Search plus unit_tests_golang) and 12 required build dependencies.

Variant Requested targets Result
e2e_mdb_kind_ubi_cloudqa_large 34 34 passed
e2e_mdb_kind_ubi_cloudqa_search_block 1 passed
e2e_mdb_openshift_search_ubi_cloudqa 1 passed
e2e_om80_kind_ubi_large 4 metrics-forwarder tests 4 passed
e2e_multi_cluster_kind 2 simulated-MC tests 2 passed
e2e_multi_cluster_2_clusters 5 selected Search tests 5 passed
private_kind_code_snippets 7 Search snippet tests 7 passed
unit_tests unit_tests_golang passed
e2e_operator_kind_ubi_cloudqa e2e_operator_upgrade_search failed after one automatic retry
required build variants 12 dependencies 12 passed

The sole failure was task mongodb_kubernetes_e2e_operator_kind_ubi_cloudqa_e2e_operator_upgrade_search_patch_c040c80dd4767cfecdbd60a529bcf15ff558a76a_6a5a08a157cb640007c484b4_26_07_17_10_49_46, executions 0 and 1. In both executions, all Search upgrade checks passed—including post-upgrade Search Running and mongot version verification—but test_database_running_after_upgrade timed out after 300 seconds waiting for AppDB member mdb-rs-2 to reach Ops Manager automation-config goal state. The agent remained at WaitHasCorrectAutomationCredentials for automation config version 9. This repeats the prior unrelated AppDB post-upgrade convergence failure; it is not a layer-1 failure or the anticipated layer-4 Search migration gap.

A configuration-audit patch, 6a5a0747b478880007d994ef, was canceled as non-evidence when generated scope showed the patch-only upgrade task was omitted. The corrected authoritative patch above generated all 68 tasks. A focused retry submission was blocked by expired Evergreen device authorization; no device approval was attempted and no retry patch was created.

Focused coverage follow-up

After rebased master c040c80dd4767cfecdbd60a529bcf15ff558a76a made e2e_search_connectivity_tool_mc_sharded executable in patches, exact-head patch 6a5a4679d981fd00073602c7 ran that task plus eight normal dependencies at accepted head 5aa0e085809d2d414485d122a7f789a3b6e0a265. All 9/9 tasks passed on execution 0 with no retries.

The target task was mongodb_kubernetes_e2e_multi_cluster_2_clusters_e2e_search_connectivity_tool_mc_sharded_patch_c040c80dd4767cfecdbd60a529bcf15ff558a76a_6a5a4679d981fd00073602c7_26_07_17_15_13_06. This closes the original exhaustive matrix’s obsolete quarantine exclusion without rerunning that matrix.

Temporary activation for the upgrade task was not committed; the branch is clean at 5aa0e085809d2d414485d122a7f789a3b6e0a265.

Automatic broad webhook patches are not validation evidence.

The full pre-stack implementation remains preserved at kube154-label-sweep-full-source-294c (294c0e8e3e6412ff2c76ba990fac9f0e6d649a76) for reconstruction of later stack layers.

Checklist

  • Jira ticket is linked and included in the title.
  • DOCSP changes are not required for this internal stack-base implementation.
  • A changelog entry is not required; the PR has the skip-changelog label.

skip-ci

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

⚠️ (this preview might not be accurate if the PR is not rebased on current master branch)

MCK 1.10.0 Release Notes

New Features

  • MongoDBOpsManager, AppDB: The mongodb-agent-monitoring sidecar container has been merged into the main
    mongodb-agent container. Both automation and monitoring now run as a single process in a single container. The
    spec.appDB.monitoringAgent field is now deprecated and has no effect; Monitoring Agent options for the AppDB —
    including log level and rotation — are configured via spec.applicationDatabase.agent and
    spec.applicationDatabase.agent.monitoringAgent, the same fields used by MongoDB resources. Enabling AppDB
    monitoring still results in rolling restarts of AppDB pods.
  • MongoDBSearch: Added support to show cluster level status of Search, Managed LoadBalancer and MetricsForwarder in the MongoDBSearch resource's status.clusters field.
  • MongoDBSearch: Added support to configure the node affinity of the MongoDB Search (mongot) pods using the MongoDBSearch CR fields spec.clusters[].nodeAffinity or spec.clusters[].shardOverrides[].nodeAffinity.

Bug Fixes

  • MongoDBUser: Fixed a bug where the connection string Secret created in the central cluster did not carry a controller owner reference to the MongoDBUser CR. The missing reference prevented Kubernetes garbage collection from cleaning up the Secret when the MongoDBUser was deleted.
  • MongoDBUser: Fixed a bug where the ownership guard on the connection string Secret was always satisfied regardless of the actual owner, allowing the operator to silently overwrite a Secret controlled by a different resource.
  • Fixed a bug where all MongoDBCommunity deployment telemetry rows incorrectly reported IsRunningEnterpriseImage = true. The field was being evaluated against the operator-level enterprise image rather than the image configured in each CR's spec, causing a misleading ~100% enterprise rate for the Community deployment type.
  • IsRunningEnterpriseImage for Community deployments is now derived from the mongod container image override in spec.statefulSet.spec.template.spec.containers, if present. When no override is set, the field correctly defaults to false, reflecting that Community CRs use the community MongoDB server image by default.
  • MongoDBOpsManager, AppDB: Fix for spec.applicationDatabase.agent.monitoringAgent.logRotate field not being
    handled properly. Additionally, added defaults for
    spec.applicationDatabase.agent.monitoringAgent.logRotate.sizeThresholdMB to 1000 and
    spec.applicationDatabase.agent.monitoringAgent.logRotate.timeThresholdHrs to 24, which are same defaults Ops Manager
    would set.
  • MongoDBSearch: The default JVM heap size (half of the memory request) is now capped at 30GB, following the mongot sizing guidance. Heap sizes above ~30GB prevent the JVM from using compressed object pointers and degrade performance. User-provided heap flags are not affected, if more than 30GB heap is required, we recommend using jvmFlags.

@anandsyncs anandsyncs added the skip-changelog Use this label in Pull Request to not require new changelog entry file label Jul 9, 2026
anandsyncs

This comment was marked as outdated.

anandsyncs added a commit that referenced this pull request Jul 14, 2026
Preserve label-routed Search lifecycle watches while incorporating upstream per-cluster status, healthy-cluster handling, toolchain updates, and metrics-forwarder enablement.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
anandsyncs

This comment was marked as outdated.

anandsyncs

This comment was marked as outdated.

@anandsyncs
anandsyncs force-pushed the search-kube154-label-sweep-lifecycle branch from 294c0e8 to a8b5018 Compare July 15, 2026 20:13
@anandsyncs anandsyncs changed the title KUBE-154: MongoDBSearch delete cleanup via label sweep KUBE-154: establish MongoDBSearch lifecycle identity Jul 15, 2026
@anandsyncs
anandsyncs force-pushed the search-kube154-label-sweep-lifecycle branch 3 times, most recently from a56bea4 to 42c8208 Compare July 16, 2026 01:06
@anandsyncs
anandsyncs requested a review from Copilot July 17, 2026 08:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Establishes stable MongoDBSearch lifecycle identity by stamping and protecting Search owner/name/namespace/UID/cluster/component labels on operator-managed resources, and by adding explicit “missing/matching/mismatched UID” adoption semantics for persisted Search/metrics state.

Changes:

  • Introduces protected Search identity labels (including mongodb.com/search-uid and component) and a helper to reapply them after CR metadata overrides while preserving unrelated labels.
  • Adds UID-aware adoption/reset semantics to Search state (ConfigMap) and metrics-forwarder topology state (StateStore-backed ConfigMap), preserving legacy state when UID markers are absent.
  • Extends unit test coverage for label protection on overrides and for UID-guarded state adoption/reset behavior.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/tls/tls_secret.go Extends TLS secret creation/update to stamp provided labels on operator-managed TLS Secret copies.
pkg/handler/labels_search.go Adds Search UID/component label constants and ReapplyProtectedSearchLabels helper for protected identity restoration.
controllers/searchcontroller/search_state.go Adds UID-guarded state read/mutate behavior; stamps identity labels + preserves existing owner refs.
controllers/searchcontroller/search_state_test.go Adds table-driven tests for Search state UID adoption/reset + identity stamping.
controllers/searchcontroller/search_construction.go Updates comments around StatefulSet override ordering and protected label restoration.
controllers/searchcontroller/mongodbsearch_reconcile_helper.go Stamps Search identity across resources; restores protected labels after overrides; passes identity labels into TLS secret creation.
controllers/searchcontroller/mongodbsearch_reconcile_helper_test.go Adds tests for override label protection and managed resource/TLS Secret identity stamping.
controllers/operator/state_store.go Adds optional owner-UID marker semantics to StateStore and preserves existing owner refs on UID mismatch.
controllers/operator/mongodbshardedcluster_controller.go Updates StateStore construction for new signature (no UID semantics).
controllers/operator/mongodbopsmanager_controller.go Updates StateStore construction for new signature (no UID semantics).
controllers/operator/appdbreplicaset_controller.go Updates StateStore construction for new signature (no UID semantics).
controllers/operator/mongodbsearchenvoy_controller.go Ensures Envoy Deployment labels restore protected Search identity after deployment overrides.
controllers/operator/mongodbsearchenvoy_controller_test.go Adds tests validating protected label restoration and UID/component stamping.
controllers/operator/mongodbsearch_metrics_controller.go Adds UID-aware StateStore usage for topology state and restores protected labels after deployment overrides.
controllers/operator/mongodbsearch_metrics_controller_test.go Adds tests validating UID adoption/reset semantics and identity labels on metrics state + deployments.
controllers/operator/mongodbsearch_controller.go Switches from read-only Search state read to no-op mutate to stamp/adopt identity metadata safely.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread controllers/searchcontroller/mongodbsearch_reconcile_helper.go Outdated
anandsyncs and others added 2 commits July 17, 2026 12:36
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@anandsyncs
anandsyncs force-pushed the search-kube154-label-sweep-lifecycle branch from 42c8208 to 5aa0e08 Compare July 17, 2026 12:00
}

ownerReferences := s.ownerReferences
if s.ownerUID != "" && len(s.readOwnerRefs) > 0 {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Stack-boundary churn (applies to the whole owner-ref layer in this PR): this readOwnerRefs merge machinery — plus the dual-owner-ref adoption in search_state.go MutateSearchState, searchResourceIdentityLabels in mongodbsearch_reconcile_helper.go, the owner-ref plumbing in pkg/tls/tls_secret.go, and their dedicated tests — is deleted wholesale by #1382 in the next layer of this stack. Since the layers land together, consider trimming this PR to the durable primitives only (the state UID data key, the mongodb.com/search-uid label, the labels param on EnsureTLSSecret, and the UID-mismatch reset) and leaving owner-ref handling untouched so #1382 removes it in one motion. Zero behavior delta at the tip of the stack, and it removes a few hundred lines of throwaway review surface from both PRs.


cm := &corev1.ConfigMap{}
require.NoError(t, c.Get(ctx, stateCMName, cm))
require.Len(t, cm.OwnerReferences, 2)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Test-side of the stack-boundary churn (companion to the state_store.go comment): the owner-reference assertions added here — plus the Len(2)/controller-ref asserts in the metrics TestOpenTopologyStateStore_UIDSemantics and the owner-ref asserts added to TestReconcileReplicaSet_CreatesResources/TestReconcile_IngressTLSSecretIdentity/TestEnsureX509ClientCertConfig_* — are all rewritten to assert.Empty(OwnerReferences) by #1382. That's ~40-50 test lines pinning a design that never reaches the tip of the stack. If this PR is trimmed to the durable primitives, these tests should assert the label-based end state once and never mention owner refs.

@viveksinghggits viveksinghggits left a comment

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.

looks pretty good.

"component": metricsForwarderLabelName,
khandler.MongoDBSearchOwnerNameLabel: search.Name,
"app": search.MetricsForwarderDeploymentNameForCluster(clusterIndex),
khandler.MongoDBSearchComponentLabel: metricsForwarderLabelName,

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.

naming of this const metricsForwarderLabelName is not part of this PR but it should be metricsForwarderLabelValue right? Let's change that maybe?

dep.Labels = merge.StringToStringMap(dep.Labels, managedLB.Deployment.MetadataWrapper.Labels)
dep.Annotations = merge.StringToStringMap(dep.Annotations, managedLB.Deployment.MetadataWrapper.Annotations)
}
dep.Labels = khandler.ReapplyProtectedSearchLabels(dep.Labels, labels)

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 ReapplyProtectedSearchLabels not be called appendProtectedSearchlabels or something like that? Or reapply is significant?

resourceName string
ownerLabels map[string]string
ownerReferences []metav1.OwnerReference
readOwnerRefs []metav1.OwnerReference

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.

q: what does readOwnerRefs have?

return labels
}

func searchResourceIdentityLabels(search *searchv1.MongoDBSearch, clusterName string) map[string]string {

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.

I like the idea of UID but was just wondering if we get into any issues if we just relied on name/namespace combination to figure out if a particular search resource created the children resource.


func searchResourceIdentityLabels(search *searchv1.MongoDBSearch, clusterName string) map[string]string {
labels := searchOwnerLabels(search, clusterName)
labels[khandler.MongoDBSearchOwnerUIDLabel] = string(search.UID)

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 this also add the component: mongot label?

Comment on lines +57 to +60
func searchStateHasCurrentUID(cm *corev1.ConfigMap, search *searchv1.MongoDBSearch) bool {
recordedUID, ok := cm.Labels[khandler.MongoDBSearchOwnerUIDLabel]
return !ok || recordedUID == string(search.UID)
}

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.

nit:

Suggested change
func searchStateHasCurrentUID(cm *corev1.ConfigMap, search *searchv1.MongoDBSearch) bool {
recordedUID, ok := cm.Labels[khandler.MongoDBSearchOwnerUIDLabel]
return !ok || recordedUID == string(search.UID)
}
func searchStateHasUID(cm *corev1.ConfigMap, uid *type) bool {
recordedUID, ok := cm.Labels[khandler.MongoDBSearchOwnerUIDLabel]
return !ok || recordedUID == string(search.UID)
}

I don't think having current is important here without defining what current is.

}
}
if !mutate(state) {

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.

I think some small comment here would be helpful for later, to understand what's happening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog Use this label in Pull Request to not require new changelog entry file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants