- 
                Notifications
    You must be signed in to change notification settings 
- Fork 22
CLOUDP-353180: Refactor replica set controller state handling, and use helper pattern #544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
| MCK 1.6.0 Release NotesNew Features
 Bug Fixes
 Other Changes
 | 
| if includeVaultAnnotations && vault.IsVaultSecretBackend() { | ||
| secrets := r.resource.GetSecretsMountedIntoDBPod() | ||
| vaultMap := make(map[string]string) | ||
| for _, s := range secrets { | ||
| path := fmt.Sprintf("%s/%s/%s", r.reconciler.VaultClient.DatabaseSecretMetadataPath(), r.resource.Namespace, s) | ||
| vaultMap = merge.StringToStringMap(vaultMap, r.reconciler.VaultClient.GetSecretAnnotation(path)) | ||
| } | ||
| path := fmt.Sprintf("%s/%s/%s", r.reconciler.VaultClient.OperatorScretMetadataPath(), r.resource.Namespace, r.resource.Spec.Credentials) | ||
| vaultMap = merge.StringToStringMap(vaultMap, r.reconciler.VaultClient.GetSecretAnnotation(path)) | ||
| for k, val := range vaultMap { | ||
| annotationsToAdd[k] = val | ||
| } | ||
| } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is in writeState method. Is vault integration related to deployment state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were storing it in annotations on successful reconciliations previously so I treated it as state:
| if vault.IsVaultSecretBackend() { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Julien-Ben I don't know a lot about Vault integration, but it seems unrelated to the deployment state to me. I also see that a similar piece of code in the sharded controller is is part of ShardedClusterReconcileHelper.Reconcile method:
mongodb-kubernetes/controllers/operator/mongodbshardedcluster_controller.go
Lines 928 to 940 in 582d248
| if vault.IsVaultSecretBackend() { | |
| secrets := sc.GetSecretsMountedIntoDBPod() | |
| vaultMap := make(map[string]string) | |
| for _, s := range secrets { | |
| path := fmt.Sprintf("%s/%s/%s", r.commonController.VaultClient.DatabaseSecretMetadataPath(), sc.Namespace, s) | |
| vaultMap = merge.StringToStringMap(vaultMap, r.commonController.VaultClient.GetSecretAnnotation(path)) | |
| } | |
| path := fmt.Sprintf("%s/%s/%s", r.commonController.VaultClient.OperatorScretMetadataPath(), sc.Namespace, sc.Spec.Credentials) | |
| vaultMap = merge.StringToStringMap(vaultMap, r.commonController.VaultClient.GetSecretAnnotation(path)) | |
| for k, val := range vaultMap { | |
| annotationsToAdd[k] = val | |
| } | |
| } | 
Should we follow the same pattern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I separated them, you were right.
Vault just needs to read annotations, and they are not state as we don't rely on them ourselves. They should be written only upon successful reconcile
I also changed how we write to lastAchievedSpec
It is actually an annotation we should change only when we achieve Running phase, not on every reconcile.
Some unit tests for the annotations
8366804    to
    bbb173b      
    Compare
  
    | testPVCFinishedResizing(t, ctx, memberClient, p, reconciledResource, statefulSet, logger) | ||
| } | ||
|  | ||
| // ===== Test for state and vault annotations handling in replicaset controller ===== | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@m1kola FYI after your review I added these unit tests
Resolved conflicts: - Removed TLS lock members logic (now blocked by validation per CLOUDP-349087) - Kept helper pattern refactoring with ReplicaSetReconcilerHelper - Removed test for deleted updateOmDeploymentDisableTLSConfiguration function
641056f    to
    6ce9706      
    Compare
  
    | } | ||
|  | ||
| // GetLastAdditionalMongodConfigByType returns the last successfully achieved AdditionalMongodConfigType for the given component. | ||
| func (m *MongoDB) GetLastAdditionalMongodConfigByType(configType AdditionalMongodConfigType) (*AdditionalMongodConfig, error) { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is now used by the standalone controller only.
The reason we don't want it any more is because it acceeds the spec with m.GetLastSpec()
We now do it only once per reconcile
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. The only concern is an unnecessary write because of two annotations.SetAnnotations calls.
| vaultMap = merge.StringToStringMap(vaultMap, r.VaultClient.GetSecretAnnotation(path)) | ||
| for k, val := range vaultMap { | ||
| annotationsToAdd[k] = val | ||
| if err := r.writeVaultAnnotations(ctx); err != nil { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both writeState and writeVaultAnnotations call annotations.SetAnnotations which gets the object and patches it.
If we can reduce write operations to the API server - that would be great.
| // Read current member count from Status once at initialization. This provides a stable view throughout | ||
| // reconciliation and prepares for eventually storing this in ConfigMap state instead of ephemeral status. | ||
| memberCountBefore := r.resource.Status.Members | ||
|  | ||
| return &ReplicaSetDeploymentState{ | ||
| LastAchievedSpec: lastAchievedSpec, | ||
| LastReconcileMemberCount: memberCountBefore, | ||
| }, nil | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Old name in the var memberCountBefore. Alternatively we can just get rid of it:
| // Read current member count from Status once at initialization. This provides a stable view throughout | |
| // reconciliation and prepares for eventually storing this in ConfigMap state instead of ephemeral status. | |
| memberCountBefore := r.resource.Status.Members | |
| return &ReplicaSetDeploymentState{ | |
| LastAchievedSpec: lastAchievedSpec, | |
| LastReconcileMemberCount: memberCountBefore, | |
| }, nil | |
| return &ReplicaSetDeploymentState{ | |
| LastAchievedSpec: lastAchievedSpec, | |
| // Read current member count from Status once at initialization. This provides a stable view throughout | |
| // reconciliation and prepares for eventually storing this in ConfigMap state instead of ephemeral status. | |
| LastReconcileMemberCount: r.resource.Status.Members, | |
| }, nil | 
| type ReplicaSetDeploymentState struct { | ||
| LastAchievedSpec *mdbv1.MongoDbSpec `json:"lastAchievedSpec"` | ||
| LastReconcileMemberCount int `json:"memberCountBefore"` | ||
| } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: does it need to be exportable?
Summary
This PR refactors the ReplicaSet controller to use the helper pattern and separate state reading/writing, matching what we already do in the ShardedCluster and OpsManager controllers.
This is a no-op refactor: no behavior changes, just reorganizing code to prepare for multi-cluster support.
What Changed
Added ReplicaSetReconcilerHelper
Separated State Operations
readState()- reads deployment state from annotationswriteState()- writes deployment state back to annotations ; write vault annotations only on successful reconciliation. In the same way it is done in the sharded controller. (note that vault is not supported for multi replica set at this point)initialize()- loads state during helper creationHelper's updateStatus() Override
Added ReplicaSetDeploymentState
LastAchievedSpecand status member count for nowNot in This PR
These will (potentially) come in follow-up PRs, in the main feature branch for multi cluster support:
Proof of work
Checklist
skip-changeloglabel if not needed