@@ -6,11 +6,11 @@ import (
66 "testing"
77 "time"
88
9- "github.com/percona/percona-server-mongodb-operator/pkg/psmdb"
109 "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/clustersync/client"
1110 "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo"
1211 "github.com/stretchr/testify/assert"
1312 "github.com/stretchr/testify/require"
13+ corev1 "k8s.io/api/core/v1"
1414 "k8s.io/apimachinery/pkg/api/meta"
1515 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1616 "k8s.io/apimachinery/pkg/types"
@@ -351,52 +351,139 @@ func (m *recordingMongoClient) UpdateUserRoles(_ context.Context, _, _ string, r
351351}
352352
353353func TestEnsureTargetMongoUser (t * testing.T ) {
354- creds := psmdb.Credentials {Username : "clustersync-cr" , Password : "new-password" }
354+ const (
355+ username = "clustersync-cr"
356+ password = "new-password"
357+ )
358+ passwordMAC := passwordAnnotationMAC ([]byte (password ))
359+
360+ secretWith := func (annotations map [string ]string ) * corev1.Secret {
361+ return & corev1.Secret {
362+ ObjectMeta : metav1.ObjectMeta {Annotations : annotations },
363+ Data : map [string ][]byte {
364+ targetUserSecretUsernameKey : []byte (username ),
365+ targetUserSecretPasswordKey : []byte (password ),
366+ },
367+ }
368+ }
369+ existingWithDesiredRoles := & mongo.User {DB : "admin" , Roles : append ([]mongo.Role (nil ), syncTargetUserRoles ... )}
355370
356371 tests := map [string ]struct {
357- mc * recordingMongoClient
358- wantErr string
359- assert func (t * testing.T , m * recordingMongoClient )
372+ mc * recordingMongoClient
373+ sec * corev1.Secret
374+ wantErr string
375+ wantMutated bool
376+ assert func (t * testing.T , m * recordingMongoClient , s * corev1.Secret )
360377 }{
361- "missing user is created with secret password" : {
362- mc : & recordingMongoClient {getUserInfoResp : nil },
363- assert : func (t * testing.T , m * recordingMongoClient ) {
378+ "missing user is created and password hash annotation is set" : {
379+ mc : & recordingMongoClient {getUserInfoResp : nil },
380+ sec : secretWith (nil ),
381+ wantMutated : true ,
382+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1.Secret ) {
364383 assert .Equal (t , 1 , m .createUserCalls )
365- assert .Equal (t , "new- password" , m .lastCreatePass )
384+ assert .Equal (t , password , m .lastCreatePass )
366385 assert .Zero (t , m .updateUserPassCalls )
367386 assert .Zero (t , m .updateRolesCalls )
387+ assert .Equal (t , passwordMAC , s .Annotations [targetUserPasswordMACAnnotation ])
368388 },
369389 },
370- "existing user has password and roles re-applied" : {
371- mc : & recordingMongoClient {getUserInfoResp : & mongo.User {DB : "admin" }},
372- assert : func (t * testing.T , m * recordingMongoClient ) {
390+ "steady state converged does no writes" : {
391+ mc : & recordingMongoClient {getUserInfoResp : existingWithDesiredRoles },
392+ sec : secretWith (map [string ]string {targetUserPasswordMACAnnotation : passwordMAC }),
393+ wantMutated : false ,
394+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1.Secret ) {
373395 assert .Zero (t , m .createUserCalls )
396+ assert .Zero (t , m .updateUserPassCalls )
397+ assert .Zero (t , m .updateRolesCalls )
398+ },
399+ },
400+ "password hash mismatch triggers UpdateUserPass and annotation refresh" : {
401+ mc : & recordingMongoClient {getUserInfoResp : existingWithDesiredRoles },
402+ sec : secretWith (map [string ]string {targetUserPasswordMACAnnotation : "stale" }),
403+ wantMutated : true ,
404+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1.Secret ) {
374405 assert .Equal (t , 1 , m .updateUserPassCalls )
375- assert .Equal (t , "new-password" , m .lastUpdatePass )
406+ assert .Equal (t , password , m .lastUpdatePass )
407+ assert .Zero (t , m .updateRolesCalls )
408+ assert .Equal (t , passwordMAC , s .Annotations [targetUserPasswordMACAnnotation ])
409+ },
410+ },
411+ "recreated secret with existing mongo user triggers UpdateUserPass and creates annotation map" : {
412+ mc : & recordingMongoClient {getUserInfoResp : existingWithDesiredRoles },
413+ sec : secretWith (nil ),
414+ wantMutated : true ,
415+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1.Secret ) {
416+ assert .Equal (t , 1 , m .updateUserPassCalls )
417+ assert .Equal (t , password , m .lastUpdatePass )
418+ assert .Zero (t , m .updateRolesCalls )
419+ require .NotNil (t , s .Annotations )
420+ assert .Equal (t , passwordMAC , s .Annotations [targetUserPasswordMACAnnotation ])
421+ },
422+ },
423+ "new cr reconcile against stale mongo user with drifted roles applies both password and roles" : {
424+ mc : & recordingMongoClient {
425+ getUserInfoResp : & mongo.User {DB : "admin" , Roles : []mongo.Role {{Role : "clusterMonitor" , DB : "admin" }}},
426+ },
427+ sec : secretWith (nil ),
428+ wantMutated : true ,
429+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1.Secret ) {
430+ assert .Equal (t , 1 , m .updateUserPassCalls )
431+ assert .Equal (t , password , m .lastUpdatePass )
432+ assert .Equal (t , 1 , m .updateRolesCalls )
433+ assert .Equal (t , syncTargetUserRoles , m .lastUpdateRoles )
434+ assert .Equal (t , passwordMAC , s .Annotations [targetUserPasswordMACAnnotation ])
435+ },
436+ },
437+ "role drift triggers UpdateUserRoles without touching password" : {
438+ mc : & recordingMongoClient {
439+ getUserInfoResp : & mongo.User {DB : "admin" , Roles : []mongo.Role {{Role : "clusterMonitor" , DB : "admin" }}},
440+ },
441+ sec : secretWith (map [string ]string {targetUserPasswordMACAnnotation : passwordMAC }),
442+ wantMutated : false ,
443+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1.Secret ) {
444+ assert .Zero (t , m .updateUserPassCalls )
376445 assert .Equal (t , 1 , m .updateRolesCalls )
377446 assert .Equal (t , syncTargetUserRoles , m .lastUpdateRoles )
378447 },
379448 },
449+ "roles in a different order are treated as equal" : {
450+ mc : & recordingMongoClient {
451+ getUserInfoResp : & mongo.User {DB : "admin" , Roles : []mongo.Role {
452+ {Role : "readWriteAnyDatabase" , DB : "admin" },
453+ {Role : "clusterManager" , DB : "admin" },
454+ {Role : "clusterMonitor" , DB : "admin" },
455+ {Role : "restore" , DB : "admin" },
456+ }},
457+ },
458+ sec : secretWith (map [string ]string {targetUserPasswordMACAnnotation : passwordMAC }),
459+ wantMutated : false ,
460+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1.Secret ) {
461+ assert .Zero (t , m .updateRolesCalls )
462+ },
463+ },
380464 "GetUserInfo error short-circuits with no writes" : {
381465 mc : & recordingMongoClient {getUserInfoErr : errors .New ("error" )},
466+ sec : secretWith (nil ),
382467 wantErr : "look up target user" ,
383- assert : func (t * testing.T , m * recordingMongoClient ) {
468+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1. Secret ) {
384469 assert .Zero (t , m .createUserCalls )
385470 assert .Zero (t , m .updateUserPassCalls )
386471 assert .Zero (t , m .updateRolesCalls )
387472 },
388473 },
389474 "CreateUser error is wrapped" : {
390475 mc : & recordingMongoClient {getUserInfoResp : nil , createUserErr : errors .New ("error" )},
476+ sec : secretWith (nil ),
391477 wantErr : "create target user" ,
392478 },
393479 "UpdateUserPass error stops before UpdateUserRoles" : {
394480 mc : & recordingMongoClient {
395481 getUserInfoResp : & mongo.User {DB : "admin" },
396482 updateUserPassErr : errors .New ("error" ),
397483 },
484+ sec : secretWith (nil ),
398485 wantErr : "sync target user password" ,
399- assert : func (t * testing.T , m * recordingMongoClient ) {
486+ assert : func (t * testing.T , m * recordingMongoClient , s * corev1. Secret ) {
400487 assert .Zero (t , m .updateRolesCalls )
401488 },
402489 },
@@ -405,21 +492,23 @@ func TestEnsureTargetMongoUser(t *testing.T) {
405492 getUserInfoResp : & mongo.User {DB : "admin" },
406493 updateRolesErr : errors .New ("error" ),
407494 },
495+ sec : secretWith (map [string ]string {targetUserPasswordMACAnnotation : passwordMAC }),
408496 wantErr : "sync target user roles" ,
409497 },
410498 }
411499
412500 for name , tc := range tests {
413501 t .Run (name , func (t * testing.T ) {
414- err := ensureTargetMongoUser (t .Context (), tc .mc , creds )
502+ mutated , err := ensureTargetMongoUser (t .Context (), tc .mc , tc . sec )
415503 if tc .wantErr != "" {
416504 require .Error (t , err )
417505 assert .Contains (t , err .Error (), tc .wantErr )
418506 } else {
419507 require .NoError (t , err )
508+ assert .Equal (t , tc .wantMutated , mutated )
420509 }
421510 if tc .assert != nil {
422- tc .assert (t , tc .mc )
511+ tc .assert (t , tc .mc , tc . sec )
423512 }
424513 })
425514 }
0 commit comments