From e2b7e9704232ce17be71fb90089f9652fee43c1a Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Fri, 16 May 2025 15:58:10 +0300 Subject: [PATCH 01/10] K8SPSMDB-1211: handle `FULL CLUSTER CRASH` error during the restore https://perconadev.atlassian.net/browse/K8SPSMDB-1211 --- pkg/controller/common/common.go | 116 ++++ pkg/controller/perconaservermongodb/backup.go | 2 +- .../perconaservermongodb/balancer.go | 6 +- .../perconaservermongodb/connections.go | 73 --- .../perconaservermongodb/connections_test.go | 3 +- .../perconaservermongodb/custom_users.go | 10 +- pkg/controller/perconaservermongodb/fcv.go | 6 +- .../perconaservermongodb/finalizers.go | 2 +- pkg/controller/perconaservermongodb/mgo.go | 16 +- .../perconaservermongodb/psmdb_controller.go | 27 +- .../perconaservermongodb/secrets.go | 46 -- .../perconaservermongodb/service.go | 8 +- pkg/controller/perconaservermongodb/smart.go | 12 +- pkg/controller/perconaservermongodb/ssl.go | 12 +- .../perconaservermongodb/statefulset.go | 2 +- .../perconaservermongodb/status_test.go | 4 +- .../perconaservermongodb/suite_test.go | 4 +- pkg/controller/perconaservermongodb/users.go | 2 +- .../perconaservermongodb/version.go | 2 +- .../perconaservermongodb/version_test.go | 7 +- .../perconaservermongodbbackup/backup.go | 2 +- .../perconaservermongodbbackup_controller.go | 15 +- .../perconaservermongodbrestore_controller.go | 16 +- .../perconaservermongodbrestore/physical.go | 533 ++++++++++-------- .../perconaservermongodbrestore/validate.go | 6 +- .../validate_test.go | 6 +- pkg/psmdb/client.go | 4 +- pkg/psmdb/provider.go | 94 +++ 28 files changed, 594 insertions(+), 442 deletions(-) create mode 100644 pkg/controller/common/common.go delete mode 100644 pkg/controller/perconaservermongodb/connections.go create mode 100644 pkg/psmdb/provider.go diff --git a/pkg/controller/common/common.go b/pkg/controller/common/common.go new file mode 100644 index 0000000000..7d5af3ee5d --- /dev/null +++ b/pkg/controller/common/common.go @@ -0,0 +1,116 @@ +package common + +import ( + "context" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" + "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" + "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo" +) + +func New(client client.Client, scheme *runtime.Scheme, newPBMFunc backup.NewPBMFunc, mongoClientProvider psmdb.MongoClientProvider) CommonReconciler { + return CommonReconciler{ + client: client, + scheme: scheme, + newPBMFunc: newPBMFunc, + mongoClientProvider: mongoClientProvider, + } +} + +type CommonReconciler struct { + client client.Client + scheme *runtime.Scheme + newPBMFunc backup.NewPBMFunc + mongoClientProvider psmdb.MongoClientProvider +} + +func (r *CommonReconciler) Client() client.Client { + return r.client +} + +func (r *CommonReconciler) Scheme() *runtime.Scheme { + return r.scheme +} + +func (r *CommonReconciler) NewPBM(ctx context.Context, cluster *api.PerconaServerMongoDB) (backup.PBM, error) { + return r.newPBMFunc(ctx, r.client, cluster) +} + +func (r *CommonReconciler) NewPBMFunc() backup.NewPBMFunc { + return r.newPBMFunc +} + +func (r *CommonReconciler) getMongoClientProvider() psmdb.MongoClientProvider { + if r.mongoClientProvider == nil { + return psmdb.NewProvider(r.client) + } + return r.mongoClientProvider +} + +func (r *CommonReconciler) MongoClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) { + return r.getMongoClientProvider().Mongo(ctx, cr, rs, role) +} + +func (r *CommonReconciler) MongosClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (mongo.Client, error) { + return r.getMongoClientProvider().Mongos(ctx, cr, role) +} + +func (r *CommonReconciler) StandaloneClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole, pod corev1.Pod) (mongo.Client, error) { + host, err := psmdb.MongoHost(ctx, r.client, cr, cr.Spec.ClusterServiceDNSMode, rs, rs.Expose.Enabled, pod) + if err != nil { + return nil, errors.Wrap(err, "failed to get mongo host") + } + return r.getMongoClientProvider().Standalone(ctx, cr, role, host, cr.TLSEnabled()) +} + +/* +// ReconcilePerconaServerMongoDB reconciles a PerconaServerMongoDB object +type ReconcilePerconaServerMongoDB struct { + // This client, initialized using mgr.Client() above, is a split client + // that reads objects from the cache and writes to the apiserver + client client.Client + scheme *runtime.Scheme + restConfig *rest.Config + + crons CronRegistry + clientcmd *clientcmd.Client + serverVersion *version.ServerVersion + reconcileIn time.Duration + mongoClientProvider psmdb.MongoClientProvider + + newCertManagerCtrlFunc tls.NewCertManagerControllerFunc + + newPBM backup.NewPBMFunc + + initImage string + + lockers lockStore +} + +// ReconcilePerconaServerMongoDBRestore reconciles a PerconaServerMongoDBRestore object +type ReconcilePerconaServerMongoDBRestore struct { + // This client, initialized using mgr.Client() above, is a split client + // that reads objects from the cache and writes to the apiserver + client client.Client + scheme *runtime.Scheme + clientcmd *clientcmd.Client + + newPBMFunc backup.NewPBMFunc +} +// ReconcilePerconaServerMongoDBBackup reconciles a PerconaServerMongoDBBackup object +type ReconcilePerconaServerMongoDBBackup struct { + // This client, initialized using mgr.Client() above, is a split client + // that reads objects from the cache and writes to the apiserver + client client.Client + scheme *runtime.Scheme + clientcmd *clientcmd.Client + + newPBMFunc backup.NewPBMFunc +} +*/ diff --git a/pkg/controller/perconaservermongodb/backup.go b/pkg/controller/perconaservermongodb/backup.go index 85c2c6e2e3..b9cb581539 100644 --- a/pkg/controller/perconaservermongodb/backup.go +++ b/pkg/controller/perconaservermongodb/backup.go @@ -60,7 +60,7 @@ func (r *ReconcilePerconaServerMongoDB) createOrUpdateBackupTask(ctx context.Con if err != nil { return errors.Wrap(err, "can't create job") } - err = setControllerReference(cr, &cjob, r.scheme) + err = setControllerReference(cr, &cjob, r.Scheme()) if err != nil { return errors.Wrapf(err, "set owner reference for backup task %s", cjob.Name) } diff --git a/pkg/controller/perconaservermongodb/balancer.go b/pkg/controller/perconaservermongodb/balancer.go index 65aa7159ce..8b1c85019b 100644 --- a/pkg/controller/perconaservermongodb/balancer.go +++ b/pkg/controller/perconaservermongodb/balancer.go @@ -4,7 +4,6 @@ import ( "context" "time" - "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" k8sErrors "k8s.io/apimachinery/pkg/api/errors" @@ -12,6 +11,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" ) func (r *ReconcilePerconaServerMongoDB) enableBalancerIfNeeded(ctx context.Context, cr *api.PerconaServerMongoDB) error { @@ -85,7 +85,7 @@ func (r *ReconcilePerconaServerMongoDB) enableBalancerIfNeeded(ctx context.Conte } } - mongosSession, err := r.mongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + mongosSession, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "failed to get mongos connection") } @@ -141,7 +141,7 @@ func (r *ReconcilePerconaServerMongoDB) disableBalancer(ctx context.Context, cr return errors.Wrapf(err, "get mongos statefulset %s", msSts.Name) } - mongosSession, err := r.mongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + mongosSession, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "failed to get mongos connection") } diff --git a/pkg/controller/perconaservermongodb/connections.go b/pkg/controller/perconaservermongodb/connections.go deleted file mode 100644 index 697f6372df..0000000000 --- a/pkg/controller/perconaservermongodb/connections.go +++ /dev/null @@ -1,73 +0,0 @@ -package perconaservermongodb - -import ( - "context" - - "github.com/pkg/errors" - corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" - "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo" -) - -type MongoClientProvider interface { - Mongo(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) - Mongos(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (mongo.Client, error) - Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole, host string, tlsEnabled bool) (mongo.Client, error) -} - -func (r *ReconcilePerconaServerMongoDB) getMongoClientProvider() MongoClientProvider { - if r.mongoClientProvider == nil { - return &mongoClientProvider{r.client} - } - return r.mongoClientProvider -} - -type mongoClientProvider struct { - k8sclient client.Client -} - -func (p *mongoClientProvider) Mongo(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) { - c, err := getInternalCredentials(ctx, p.k8sclient, cr, role) - if err != nil { - return nil, errors.Wrap(err, "failed to get credentials") - } - - return psmdb.MongoClient(ctx, p.k8sclient, cr, rs, c) -} - -func (p *mongoClientProvider) Mongos(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (mongo.Client, error) { - c, err := getInternalCredentials(ctx, p.k8sclient, cr, role) - if err != nil { - return nil, errors.Wrap(err, "failed to get credentials") - } - - return psmdb.MongosClient(ctx, p.k8sclient, cr, c) -} - -func (p *mongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole, host string, tlsEnabled bool) (mongo.Client, error) { - c, err := getInternalCredentials(ctx, p.k8sclient, cr, role) - if err != nil { - return nil, errors.Wrap(err, "failed to get credentials") - } - - return psmdb.StandaloneClient(ctx, p.k8sclient, cr, c, host, tlsEnabled) -} - -func (r *ReconcilePerconaServerMongoDB) mongoClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) { - return r.getMongoClientProvider().Mongo(ctx, cr, rs, role) -} - -func (r *ReconcilePerconaServerMongoDB) mongosClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (mongo.Client, error) { - return r.getMongoClientProvider().Mongos(ctx, cr, role) -} - -func (r *ReconcilePerconaServerMongoDB) standaloneClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole, pod corev1.Pod) (mongo.Client, error) { - host, err := psmdb.MongoHost(ctx, r.client, cr, cr.Spec.ClusterServiceDNSMode, rs, rs.Expose.Enabled, pod) - if err != nil { - return nil, errors.Wrap(err, "failed to get mongo host") - } - return r.getMongoClientProvider().Standalone(ctx, cr, role, host, cr.TLSEnabled()) -} diff --git a/pkg/controller/perconaservermongodb/connections_test.go b/pkg/controller/perconaservermongodb/connections_test.go index a51b532ce4..93531c3e55 100644 --- a/pkg/controller/perconaservermongodb/connections_test.go +++ b/pkg/controller/perconaservermongodb/connections_test.go @@ -19,6 +19,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo" @@ -158,7 +159,7 @@ func TestConnectionLeaks(t *testing.T) { connectionCount := new(int) r := buildFakeClient(obj...) - r.mongoClientProvider = &fakeMongoClientProvider{pods: rsPods, cr: cr, connectionCount: connectionCount} + r.CommonReconciler = common.New(r.Client(), r.Scheme(), r.NewPBMFunc(), &fakeMongoClientProvider{pods: rsPods, cr: cr, connectionCount: connectionCount}) r.serverVersion = &version.ServerVersion{Platform: version.PlatformKubernetes} r.crons = NewCronRegistry() diff --git a/pkg/controller/perconaservermongodb/custom_users.go b/pkg/controller/perconaservermongodb/custom_users.go index 05f8eb81c4..f7001e01f9 100644 --- a/pkg/controller/perconaservermongodb/custom_users.go +++ b/pkg/controller/perconaservermongodb/custom_users.go @@ -35,9 +35,9 @@ func (r *ReconcilePerconaServerMongoDB) reconcileCustomUsers(ctx context.Context var err error var mongoCli mongo.Client if cr.Spec.Sharding.Enabled { - mongoCli, err = r.mongosClientWithRole(ctx, cr, api.RoleUserAdmin) + mongoCli, err = r.MongosClientWithRole(ctx, cr, api.RoleUserAdmin) } else { - mongoCli, err = r.mongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleUserAdmin) + mongoCli, err = r.MongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleUserAdmin) } if err != nil { return errors.Wrap(err, "failed to get mongo client") @@ -310,7 +310,8 @@ func updatePass( user *api.User, userInfo *mongo.User, secret *corev1.Secret, - annotationKey, passKey string) error { + annotationKey, passKey string, +) error { log := logf.FromContext(ctx) if userInfo == nil || user.IsExternalDB() { @@ -395,7 +396,8 @@ func createUser( mongoCli mongo.Client, user *api.User, secret *corev1.Secret, - annotationKey, passKey string) error { + annotationKey, passKey string, +) error { log := logf.FromContext(ctx) roles := make([]mongo.Role, 0) diff --git a/pkg/controller/perconaservermongodb/fcv.go b/pkg/controller/perconaservermongodb/fcv.go index 50ca8e2fc9..cb71e5708c 100644 --- a/pkg/controller/perconaservermongodb/fcv.go +++ b/pkg/controller/perconaservermongodb/fcv.go @@ -12,7 +12,7 @@ import ( ) func (r *ReconcilePerconaServerMongoDB) getFCV(ctx context.Context, cr *api.PerconaServerMongoDB) (string, error) { - c, err := r.mongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleClusterAdmin) + c, err := r.MongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleClusterAdmin) if err != nil { return "", errors.Wrap(err, "failed to get connection") } @@ -40,9 +40,9 @@ func (r *ReconcilePerconaServerMongoDB) setFCV(ctx context.Context, cr *api.Perc var connErr error if cr.Spec.Sharding.Enabled { - cli, connErr = r.mongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + cli, connErr = r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) } else { - cli, connErr = r.mongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleClusterAdmin) + cli, connErr = r.MongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleClusterAdmin) } if connErr != nil { diff --git a/pkg/controller/perconaservermongodb/finalizers.go b/pkg/controller/perconaservermongodb/finalizers.go index 544d475da2..c1d003d0f8 100644 --- a/pkg/controller/perconaservermongodb/finalizers.go +++ b/pkg/controller/perconaservermongodb/finalizers.go @@ -85,7 +85,7 @@ func (r *ReconcilePerconaServerMongoDB) checkFinalizers(ctx context.Context, cr } func (r *ReconcilePerconaServerMongoDB) deleteAllPITRChunks(ctx context.Context, cr *api.PerconaServerMongoDB) error { - pbmc, err := r.newPBM(ctx, r.client, cr) + pbmc, err := r.NewPBM(ctx, cr) if err != nil { return errors.Wrap(err, "new pbm") } diff --git a/pkg/controller/perconaservermongodb/mgo.go b/pkg/controller/perconaservermongodb/mgo.go index d127117cf8..d5548fca57 100644 --- a/pkg/controller/perconaservermongodb/mgo.go +++ b/pkg/controller/perconaservermongodb/mgo.go @@ -95,7 +95,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileCluster(ctx context.Context, cr } } - cli, err := r.mongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) + cli, err := r.MongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) if err != nil { if cr.Spec.Unmanaged { return api.AppStateInit, nil, nil @@ -193,7 +193,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileCluster(ctx context.Context, cr replset.ClusterRole == api.ClusterRoleShardSvr && len(mongosPods) > 0 && cr.Spec.Sharding.Mongos.Size > 0 { - mongosSession, err := r.mongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + mongosSession, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) if err != nil { return api.AppStateError, nil, errors.Wrap(err, "failed to get mongos connection") } @@ -571,7 +571,7 @@ func (r *ReconcilePerconaServerMongoDB) removeRSFromShard(ctx context.Context, c return nil } - cli, err := r.mongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + cli, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) if err != nil { return errors.Errorf("failed to get mongos connection: %v", err) } @@ -621,7 +621,7 @@ func (r *ReconcilePerconaServerMongoDB) handleRsAddToShard(ctx context.Context, return errors.Wrapf(err, "get rsPod %s host", rspod.Name) } - cli, err := r.mongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + cli, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "failed to get mongos client") } @@ -724,7 +724,7 @@ func (r *ReconcilePerconaServerMongoDB) handleReplsetInit(ctx context.Context, c time.Sleep(time.Second * 5) log.Info("creating user admin", "replset", replsetName, "pod", pod.Name, "user", api.RoleUserAdmin) - userAdmin, err := getInternalCredentials(ctx, r.client, cr, api.RoleUserAdmin) + userAdmin, err := psmdb.GetCredentials(ctx, r.client, cr, api.RoleUserAdmin) if err != nil { return nil, nil, errors.Wrap(err, "failed to get userAdmin credentials") } @@ -757,7 +757,7 @@ func (r *ReconcilePerconaServerMongoDB) handleReplicaSetNoPrimary(ctx context.Co } log.Info("Connecting to pod", "pod", pod.Name, "user", api.RoleClusterAdmin) - cli, err := r.standaloneClientWithRole(ctx, cr, replset, api.RoleClusterAdmin, pod) + cli, err := r.StandaloneClientWithRole(ctx, cr, replset, api.RoleClusterAdmin, pod) if err != nil { return errors.Wrap(err, "get standalone mongo client") } @@ -922,7 +922,7 @@ func compareRoles(x []mongo.Role, y []mongo.Role) bool { func (r *ReconcilePerconaServerMongoDB) createOrUpdateSystemUsers(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.ReplsetSpec) error { log := logf.FromContext(ctx) - cli, err := r.mongoClientWithRole(ctx, cr, replset, api.RoleUserAdmin) + cli, err := r.MongoClientWithRole(ctx, cr, replset, api.RoleUserAdmin) if err != nil { return errors.Wrap(err, "failed to get mongo client") } @@ -1013,7 +1013,7 @@ func (r *ReconcilePerconaServerMongoDB) createOrUpdateSystemUsers(ctx context.Co } for _, role := range users { - creds, err := getInternalCredentials(ctx, r.client, cr, role) + creds, err := psmdb.GetCredentials(ctx, r.client, cr, role) if err != nil { log.Error(err, "failed to get credentials", "role", role) continue diff --git a/pkg/controller/perconaservermongodb/psmdb_controller.go b/pkg/controller/perconaservermongodb/psmdb_controller.go index 63f5818933..23d0e95fd1 100644 --- a/pkg/controller/perconaservermongodb/psmdb_controller.go +++ b/pkg/controller/perconaservermongodb/psmdb_controller.go @@ -35,6 +35,7 @@ import ( "github.com/percona/percona-server-mongodb-operator/clientcmd" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" @@ -87,13 +88,12 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) { } return &ReconcilePerconaServerMongoDB{ + CommonReconciler: common.New(client, mgr.GetScheme(), backup.NewPBM, nil), client: client, - scheme: mgr.GetScheme(), serverVersion: sv, reconcileIn: time.Second * 5, crons: NewCronRegistry(), lockers: newLockStore(), - newPBM: backup.NewPBM, restConfig: mgr.GetConfig(), newCertManagerCtrlFunc: tls.NewCertManagerController, @@ -171,22 +171,19 @@ func NewCronRegistry() CronRegistry { // ReconcilePerconaServerMongoDB reconciles a PerconaServerMongoDB object type ReconcilePerconaServerMongoDB struct { + common.CommonReconciler // This client, initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver client client.Client - scheme *runtime.Scheme restConfig *rest.Config - crons CronRegistry - clientcmd *clientcmd.Client - serverVersion *version.ServerVersion - reconcileIn time.Duration - mongoClientProvider MongoClientProvider + crons CronRegistry + clientcmd *clientcmd.Client + serverVersion *version.ServerVersion + reconcileIn time.Duration newCertManagerCtrlFunc tls.NewCertManagerControllerFunc - newPBM backup.NewPBMFunc - initImage string lockers lockStore @@ -844,7 +841,7 @@ func (r *ReconcilePerconaServerMongoDB) checkIfUserDataExistInRS(ctx context.Con return errors.Wrap(err, "failed to set port") } - mc, err := r.mongoClientWithRole(ctx, cr, rs, api.RoleClusterAdmin) + mc, err := r.MongoClientWithRole(ctx, cr, rs, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "dial:") } @@ -887,7 +884,7 @@ func (r *ReconcilePerconaServerMongoDB) ensureSecurityKey(ctx context.Context, c if err != nil && k8serrors.IsNotFound(err) { created = true if setOwner { - err = setControllerReference(cr, key, r.scheme) + err = setControllerReference(cr, key, r.Scheme()) if err != nil { return false, errors.Wrap(err, "set owner ref") } @@ -1185,7 +1182,7 @@ func deleteConfigMapIfExists(ctx context.Context, cl client.Client, cr *api.Perc } func (r *ReconcilePerconaServerMongoDB) createOrUpdateConfigMap(ctx context.Context, cr *api.PerconaServerMongoDB, configMap *corev1.ConfigMap) error { - err := setControllerReference(cr, configMap, r.scheme) + err := setControllerReference(cr, configMap, r.Scheme()) if err != nil { return errors.Wrapf(err, "failed to set controller ref for config map %s", configMap.Name) } @@ -1264,7 +1261,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileMongosStatefulset(ctx context.C } sts := psmdb.MongosStatefulset(cr) - err = setControllerReference(cr, sts, r.scheme) + err = setControllerReference(cr, sts, r.Scheme()) if err != nil { return errors.Wrapf(err, "set owner ref for statefulset %s", sts.Name) } @@ -1491,7 +1488,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcilePDB(ctx context.Context, cr *ap if cr.CompareVersion("1.17.0") < 0 { pdb.Labels = nil } - err := setControllerReference(owner, pdb, r.scheme) + err := setControllerReference(owner, pdb, r.Scheme()) if err != nil { return errors.Wrap(err, "set owner reference") } diff --git a/pkg/controller/perconaservermongodb/secrets.go b/pkg/controller/perconaservermongodb/secrets.go index c618b65089..d3e98395f4 100644 --- a/pkg/controller/perconaservermongodb/secrets.go +++ b/pkg/controller/perconaservermongodb/secrets.go @@ -10,58 +10,12 @@ import ( k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" "github.com/percona/percona-server-mongodb-operator/pkg/naming" - "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/secret" ) -func getUserSecret(ctx context.Context, cl client.Reader, cr *api.PerconaServerMongoDB, name string) (corev1.Secret, error) { - secrets := corev1.Secret{} - err := cl.Get(ctx, types.NamespacedName{Name: name, Namespace: cr.Namespace}, &secrets) - return secrets, errors.Wrap(err, "get user secrets") -} - -func getInternalCredentials(ctx context.Context, cl client.Reader, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (psmdb.Credentials, error) { - return getCredentials(ctx, cl, cr, api.UserSecretName(cr), role) -} - -func getCredentials(ctx context.Context, cl client.Reader, cr *api.PerconaServerMongoDB, name string, role api.SystemUserRole) (psmdb.Credentials, error) { - creds := psmdb.Credentials{} - usersSecret, err := getUserSecret(ctx, cl, cr, name) - if err != nil { - return creds, errors.Wrap(err, "failed to get user secret") - } - - switch role { - case api.RoleDatabaseAdmin: - creds.Username = string(usersSecret.Data[api.EnvMongoDBDatabaseAdminUser]) - creds.Password = string(usersSecret.Data[api.EnvMongoDBDatabaseAdminPassword]) - case api.RoleClusterAdmin: - creds.Username = string(usersSecret.Data[api.EnvMongoDBClusterAdminUser]) - creds.Password = string(usersSecret.Data[api.EnvMongoDBClusterAdminPassword]) - case api.RoleUserAdmin: - creds.Username = string(usersSecret.Data[api.EnvMongoDBUserAdminUser]) - creds.Password = string(usersSecret.Data[api.EnvMongoDBUserAdminPassword]) - case api.RoleClusterMonitor: - creds.Username = string(usersSecret.Data[api.EnvMongoDBClusterMonitorUser]) - creds.Password = string(usersSecret.Data[api.EnvMongoDBClusterMonitorPassword]) - case api.RoleBackup: - creds.Username = string(usersSecret.Data[api.EnvMongoDBBackupUser]) - creds.Password = string(usersSecret.Data[api.EnvMongoDBBackupPassword]) - default: - return creds, errors.Errorf("not implemented for role: %s", role) - } - - if creds.Username == "" || creds.Password == "" { - return creds, errors.Errorf("can't find credentials for role %s", role) - } - - return creds, nil -} - func (r *ReconcilePerconaServerMongoDB) reconcileUsersSecret(ctx context.Context, cr *api.PerconaServerMongoDB) error { secretObj := corev1.Secret{} err := r.client.Get(ctx, diff --git a/pkg/controller/perconaservermongodb/service.go b/pkg/controller/perconaservermongodb/service.go index 26883f5688..8824b9ae9c 100644 --- a/pkg/controller/perconaservermongodb/service.go +++ b/pkg/controller/perconaservermongodb/service.go @@ -31,7 +31,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileReplsetServices(ctx context.Con for _, rs := range repls { // Create headless service service := psmdb.Service(cr, rs) - if err := setControllerReference(cr, service, r.scheme); err != nil { + if err := setControllerReference(cr, service, r.Scheme()); err != nil { return errors.Wrapf(err, "set owner ref for service %s", service.Name) } if err := r.createOrUpdateSvc(ctx, cr, service, true); err != nil { @@ -84,7 +84,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileMongosSvc(ctx context.Context, func (r *ReconcilePerconaServerMongoDB) ensureExternalServices(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.ReplsetSpec, podList *corev1.PodList) error { for _, pod := range podList.Items { service := psmdb.ExternalService(cr, replset, pod.Name) - err := setControllerReference(cr, service, r.scheme) + err := setControllerReference(cr, service, r.Scheme()) if err != nil { return errors.Wrapf(err, "set owner ref for Service %s", service.Name) } @@ -111,7 +111,7 @@ func (r *ReconcilePerconaServerMongoDB) exportService(ctx context.Context, cr *a return nil } se := mcs.ServiceExport(cr.Namespace, svc.Name, ls) - if err := setControllerReference(cr, se, r.scheme); err != nil { + if err := setControllerReference(cr, se, r.Scheme()); err != nil { return errors.Wrapf(err, "set owner ref for serviceexport %s", se.Name) } if err := r.createOrUpdate(ctx, se); err != nil { @@ -261,7 +261,7 @@ func (r *ReconcilePerconaServerMongoDB) removeOutdatedMongosSvc(ctx context.Cont func (r *ReconcilePerconaServerMongoDB) createOrUpdateMongosSvc(ctx context.Context, cr *api.PerconaServerMongoDB, name string) error { svc := psmdb.MongosService(cr, name) - err := setControllerReference(cr, &svc, r.scheme) + err := setControllerReference(cr, &svc, r.Scheme()) if err != nil { return errors.Wrapf(err, "set owner ref for service %s", svc.Name) } diff --git a/pkg/controller/perconaservermongodb/smart.go b/pkg/controller/perconaservermongodb/smart.go index e3951c2471..0040e23a66 100644 --- a/pkg/controller/perconaservermongodb/smart.go +++ b/pkg/controller/perconaservermongodb/smart.go @@ -151,7 +151,7 @@ func (r *ReconcilePerconaServerMongoDB) smartUpdate(ctx context.Context, cr *api return nil } - hasActiveJobs, err := backup.HasActiveJobs(ctx, r.newPBM, r.client, cr, backup.Job{}, backup.NotPITRLock) + hasActiveJobs, err := backup.HasActiveJobs(ctx, r.NewPBMFunc(), r.client, cr, backup.Job{}, backup.NotPITRLock) if err != nil { if cr.Status.State == api.AppStateError { log.Info("Failed to check active jobs. Proceeding with Smart Update because the cluster is in an error state", "error", err.Error()) @@ -201,7 +201,7 @@ func (r *ReconcilePerconaServerMongoDB) smartUpdate(ctx context.Context, cr *api if sfs.Labels[naming.LabelKubernetesComponent] != "nonVoting" && len(primaryPod.Name) > 0 { forceStepDown := replset.Size == 1 log.Info("doing step down...", "force", forceStepDown) - client, err := r.mongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) + client, err := r.MongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) if err != nil { return fmt.Errorf("failed to get mongo client: %v", err) } @@ -345,7 +345,7 @@ func (r *ReconcilePerconaServerMongoDB) setPrimary(ctx context.Context, cr *api. func (r *ReconcilePerconaServerMongoDB) stepDownPod(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, pod corev1.Pod, seconds int) error { log := logf.FromContext(ctx) - mgoClient, err := r.standaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) + mgoClient, err := r.StandaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) if err != nil { return errors.Wrap(err, "failed to create standalone client") } @@ -364,7 +364,7 @@ func (r *ReconcilePerconaServerMongoDB) stepDownPod(ctx context.Context, cr *api func (r *ReconcilePerconaServerMongoDB) freezePod(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, pod corev1.Pod, seconds int) error { log := logf.FromContext(ctx) - mgoClient, err := r.standaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) + mgoClient, err := r.StandaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) if err != nil { return errors.Wrap(err, "failed to create standalone client") } @@ -383,7 +383,7 @@ func (r *ReconcilePerconaServerMongoDB) freezePod(ctx context.Context, cr *api.P func (r *ReconcilePerconaServerMongoDB) isPodPrimary(ctx context.Context, cr *api.PerconaServerMongoDB, pod corev1.Pod, rs *api.ReplsetSpec) (bool, error) { log := logf.FromContext(ctx) - mgoClient, err := r.standaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) + mgoClient, err := r.StandaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) if err != nil { return false, errors.Wrap(err, "failed to create standalone client") } @@ -434,7 +434,7 @@ func (r *ReconcilePerconaServerMongoDB) smartMongosUpdate(ctx context.Context, c return nil } - hasActiveJobs, err := backup.HasActiveJobs(ctx, r.newPBM, r.client, cr, backup.Job{}, backup.NotPITRLock) + hasActiveJobs, err := backup.HasActiveJobs(ctx, r.NewPBMFunc(), r.client, cr, backup.Job{}, backup.NotPITRLock) if err != nil { return errors.Wrap(err, "failed to check active jobs") } diff --git a/pkg/controller/perconaservermongodb/ssl.go b/pkg/controller/perconaservermongodb/ssl.go index 105193e00a..a8c7f29e1f 100644 --- a/pkg/controller/perconaservermongodb/ssl.go +++ b/pkg/controller/perconaservermongodb/ssl.go @@ -103,7 +103,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileSSL(ctx context.Context, cr *ap } func (r *ReconcilePerconaServerMongoDB) isCertManagerInstalled(ctx context.Context, ns string) (bool, error) { - c := r.newCertManagerCtrlFunc(r.client, r.scheme, true) + c := r.newCertManagerCtrlFunc(r.client, r.Scheme(), true) err := c.Check(ctx, r.restConfig, ns) if err != nil { switch { @@ -150,7 +150,7 @@ func (r *ReconcilePerconaServerMongoDB) doAllStsHasLatestTLS(ctx context.Context func (r *ReconcilePerconaServerMongoDB) createSSLByCertManager(ctx context.Context, cr *api.PerconaServerMongoDB) error { log := logf.FromContext(ctx).WithName("createSSLByCertManager") - dryController := r.newCertManagerCtrlFunc(r.client, r.scheme, true) + dryController := r.newCertManagerCtrlFunc(r.client, r.Scheme(), true) // checking if certificates will be updated applyStatus, err := r.applyCertManagerCertificates(ctx, cr, dryController) if err != nil { @@ -236,7 +236,7 @@ func (r *ReconcilePerconaServerMongoDB) createSSLByCertManager(ctx context.Conte return errors.Wrap(err, "update cert mangager certs") } - c := r.newCertManagerCtrlFunc(r.client, r.scheme, false) + c := r.newCertManagerCtrlFunc(r.client, r.Scheme(), false) if cr.CompareVersion("1.15.0") >= 0 { if err := c.DeleteDeprecatedIssuerIfExists(ctx, cr); err != nil { return errors.Wrap(err, "delete deprecated issuer") @@ -293,7 +293,7 @@ func (r *ReconcilePerconaServerMongoDB) updateCertManagerCerts(ctx context.Conte } } - c := r.newCertManagerCtrlFunc(r.client, r.scheme, false) + c := r.newCertManagerCtrlFunc(r.client, r.Scheme(), false) log.Info("applying new certificates") if _, err := r.applyCertManagerCertificates(ctx, cr, c); err != nil { return errors.Wrap(err, "failed to apply cert-manager certificates") @@ -309,7 +309,7 @@ func (r *ReconcilePerconaServerMongoDB) updateCertManagerCerts(ctx context.Conte // mergeNewCA overwrites current ssl secrets with the old ones, but merges ca.crt from the current secret func (r *ReconcilePerconaServerMongoDB) mergeNewCA(ctx context.Context, cr *api.PerconaServerMongoDB) error { log := logf.FromContext(ctx) - c := tls.NewCertManagerController(r.client, r.scheme, false) + c := tls.NewCertManagerController(r.client, r.Scheme(), false) // In versions 1.14.0 and below, these secrets contained different ca.crt oldCA, err := c.GetMergedCA(ctx, cr, []string{ api.SSLInternalSecretName(cr) + "-old", @@ -451,7 +451,7 @@ func (r *ReconcilePerconaServerMongoDB) createSSLManually(ctx context.Context, c data["tls.crt"] = tlsCert data["tls.key"] = key - owner, err := OwnerRef(cr, r.scheme) + owner, err := OwnerRef(cr, r.Scheme()) if err != nil { return err } diff --git a/pkg/controller/perconaservermongodb/statefulset.go b/pkg/controller/perconaservermongodb/statefulset.go index d71d221e74..52d29f24bf 100644 --- a/pkg/controller/perconaservermongodb/statefulset.go +++ b/pkg/controller/perconaservermongodb/statefulset.go @@ -91,7 +91,7 @@ func (r *ReconcilePerconaServerMongoDB) getStatefulsetFromReplset(ctx context.Co } sfs := psmdb.NewStatefulSet(sfsName, cr.Namespace) - err := setControllerReference(cr, sfs, r.scheme) + err := setControllerReference(cr, sfs, r.Scheme()) if err != nil { return nil, errors.Wrapf(err, "set owner ref for StatefulSet %s", sfs.Name) } diff --git a/pkg/controller/perconaservermongodb/status_test.go b/pkg/controller/perconaservermongodb/status_test.go index 1f1ab35c9a..def3032ef5 100644 --- a/pkg/controller/perconaservermongodb/status_test.go +++ b/pkg/controller/perconaservermongodb/status_test.go @@ -14,6 +14,7 @@ import ( mcs "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" fakeBackup "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup/fake" faketls "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/tls/fake" "github.com/percona/percona-server-mongodb-operator/version" @@ -38,10 +39,9 @@ func buildFakeClient(objs ...client.Object) *ReconcilePerconaServerMongoDB { cl := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).WithStatusSubresource(objs...).Build() return &ReconcilePerconaServerMongoDB{ + CommonReconciler: common.New(cl, s, fakeBackup.NewPBM, nil), client: cl, - scheme: s, lockers: newLockStore(), - newPBM: fakeBackup.NewPBM, newCertManagerCtrlFunc: faketls.NewCertManagerController, } } diff --git a/pkg/controller/perconaservermongodb/suite_test.go b/pkg/controller/perconaservermongodb/suite_test.go index 9aa5391f9b..bbe3abcdcd 100644 --- a/pkg/controller/perconaservermongodb/suite_test.go +++ b/pkg/controller/perconaservermongodb/suite_test.go @@ -19,6 +19,7 @@ import ( "github.com/percona/percona-server-mongodb-operator/clientcmd" "github.com/percona/percona-server-mongodb-operator/pkg/apis" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/tls" "github.com/percona/percona-server-mongodb-operator/version" @@ -79,12 +80,11 @@ func reconciler() *ReconcilePerconaServerMongoDB { return (&ReconcilePerconaServerMongoDB{ client: k8sClient, - scheme: k8sClient.Scheme(), + CommonReconciler: common.New(k8sClient, k8sClient.Scheme(), backup.NewPBM, nil), crons: NewCronRegistry(), lockers: newLockStore(), clientcmd: cli, restConfig: cfg, - newPBM: backup.NewPBM, newCertManagerCtrlFunc: tls.NewCertManagerController, serverVersion: &version.ServerVersion{ Platform: version.PlatformKubernetes, diff --git a/pkg/controller/perconaservermongodb/users.go b/pkg/controller/perconaservermongodb/users.go index 05105bd8d3..cec509d12c 100644 --- a/pkg/controller/perconaservermongodb/users.go +++ b/pkg/controller/perconaservermongodb/users.go @@ -319,7 +319,7 @@ func (r *ReconcilePerconaServerMongoDB) updateUsers(ctx context.Context, cr *api for i := range repls { replset := repls[i] grp.Go(func() error { - client, err := r.mongoClientWithRole(gCtx, cr, replset, api.RoleUserAdmin) + client, err := r.MongoClientWithRole(gCtx, cr, replset, api.RoleUserAdmin) if err != nil { return errors.Wrap(err, "dial:") } diff --git a/pkg/controller/perconaservermongodb/version.go b/pkg/controller/perconaservermongodb/version.go index cc89fee9c0..118a9f22e2 100644 --- a/pkg/controller/perconaservermongodb/version.go +++ b/pkg/controller/perconaservermongodb/version.go @@ -579,7 +579,7 @@ func (r *ReconcilePerconaServerMongoDB) fetchVersionFromMongo(ctx context.Contex return nil } - session, err := r.mongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) + session, err := r.MongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "dial") } diff --git a/pkg/controller/perconaservermongodb/version_test.go b/pkg/controller/perconaservermongodb/version_test.go index 16effab84b..644276a440 100644 --- a/pkg/controller/perconaservermongodb/version_test.go +++ b/pkg/controller/perconaservermongodb/version_test.go @@ -24,6 +24,7 @@ import ( "github.com/percona/percona-server-mongodb-operator/pkg/apis" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/k8s" "github.com/percona/percona-server-mongodb-operator/version" ) @@ -597,9 +598,9 @@ func TestVersionMeta(t *testing.T) { cl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&tt.cr, &operatorDepl).Build() sv := &version.ServerVersion{Platform: version.PlatformKubernetes} r := &ReconcilePerconaServerMongoDB{ - client: cl, - scheme: scheme, - serverVersion: sv, + CommonReconciler: common.New(cl, scheme, nil, nil), + client: cl, + serverVersion: sv, } if err := r.setCRVersion(context.TODO(), &tt.cr); err != nil { diff --git a/pkg/controller/perconaservermongodbbackup/backup.go b/pkg/controller/perconaservermongodbbackup/backup.go index 7893806445..74fcd0f47f 100644 --- a/pkg/controller/perconaservermongodbbackup/backup.go +++ b/pkg/controller/perconaservermongodbbackup/backup.go @@ -43,7 +43,7 @@ func (r *ReconcilePerconaServerMongoDBBackup) newBackup(ctx context.Context, clu if cluster == nil { return new(Backup), nil } - cn, err := r.newPBMFunc(ctx, r.client, cluster) + cn, err := r.NewPBM(ctx, cluster) if err != nil { return nil, errors.Wrap(err, "create pbm object") } diff --git a/pkg/controller/perconaservermongodbbackup/perconaservermongodbbackup_controller.go b/pkg/controller/perconaservermongodbbackup/perconaservermongodbbackup_controller.go index 209a6ea8d2..8ba419d4d1 100644 --- a/pkg/controller/perconaservermongodbbackup/perconaservermongodbbackup_controller.go +++ b/pkg/controller/perconaservermongodbbackup/perconaservermongodbbackup_controller.go @@ -11,7 +11,6 @@ import ( corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -30,6 +29,7 @@ import ( "github.com/percona/percona-server-mongodb-operator/clientcmd" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" @@ -59,10 +59,9 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) { } return &ReconcilePerconaServerMongoDBBackup{ - client: mgr.GetClient(), - scheme: mgr.GetScheme(), - newPBMFunc: backup.NewPBM, - clientcmd: cli, + CommonReconciler: common.New(mgr.GetClient(), mgr.GetScheme(), backup.NewPBM, nil), + client: mgr.GetClient(), + clientcmd: cli, }, nil } @@ -87,13 +86,11 @@ var _ reconcile.Reconciler = &ReconcilePerconaServerMongoDBBackup{} // ReconcilePerconaServerMongoDBBackup reconciles a PerconaServerMongoDBBackup object type ReconcilePerconaServerMongoDBBackup struct { + common.CommonReconciler // This client, initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver client client.Client - scheme *runtime.Scheme clientcmd *clientcmd.Client - - newPBMFunc backup.NewPBMFunc } // Reconcile reads that state of the cluster for a PerconaServerMongoDBBackup object and makes changes based on the state read @@ -222,7 +219,7 @@ func (r *ReconcilePerconaServerMongoDBBackup) reconcile( return status, errors.Wrap(err, "failed to run backup") } - cjobs, err := backup.HasActiveJobs(ctx, r.newPBMFunc, r.client, cluster, backup.NewBackupJob(cr.Name), backup.NotPITRLock) + cjobs, err := backup.HasActiveJobs(ctx, r.NewPBMFunc(), r.client, cluster, backup.NewBackupJob(cr.Name), backup.NotPITRLock) if err != nil { return status, errors.Wrap(err, "check for concurrent jobs") } diff --git a/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go b/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go index 56e8ed1084..afb86cc662 100644 --- a/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go +++ b/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go @@ -10,7 +10,6 @@ import ( corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/util/retry" @@ -26,6 +25,7 @@ import ( "github.com/percona/percona-server-mongodb-operator/clientcmd" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" @@ -52,10 +52,9 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) { } return &ReconcilePerconaServerMongoDBRestore{ - client: mgr.GetClient(), - scheme: mgr.GetScheme(), - clientcmd: cli, - newPBMFunc: backup.NewPBM, + CommonReconciler: common.New(mgr.GetClient(), mgr.GetScheme(), backup.NewPBM, nil), + client: mgr.GetClient(), + clientcmd: cli, }, nil } @@ -81,11 +80,10 @@ var _ reconcile.Reconciler = &ReconcilePerconaServerMongoDBRestore{} type ReconcilePerconaServerMongoDBRestore struct { // This client, initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver - client client.Client - scheme *runtime.Scheme - clientcmd *clientcmd.Client + common.CommonReconciler - newPBMFunc backup.NewPBMFunc + client client.Client // TODO: use CommonReconciler client + clientcmd *clientcmd.Client } // Reconcile reads that state of the cluster for a PerconaServerMongoDBRestore object and makes changes based on the state read diff --git a/pkg/controller/perconaservermongodbrestore/physical.go b/pkg/controller/perconaservermongodbrestore/physical.go index 7be56ba42d..7cd0bd2fe8 100644 --- a/pkg/controller/perconaservermongodbrestore/physical.go +++ b/pkg/controller/perconaservermongodbrestore/physical.go @@ -4,14 +4,17 @@ import ( "bytes" "context" "encoding/json" + stdError "errors" "fmt" "strings" "time" "github.com/pkg/errors" + "go.mongodb.org/mongo-driver/x/mongo/driver/topology" "gopkg.in/yaml.v2" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" @@ -91,33 +94,35 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( status.State = psmdbv1.RestoreStateWaiting } - if err := r.prepareStatefulSetsForPhysicalRestore(ctx, cluster); err != nil { - return status, errors.Wrap(err, "prepare statefulsets for physical restore") - } - - sfsReady, err := r.checkIfStatefulSetsAreReadyForPhysicalRestore(ctx, cluster) - if err != nil { - return status, errors.Wrap(err, "check if statefulsets are ready for physical restore") - } - - if (!sfsReady && cr.Status.State != psmdbv1.RestoreStateRunning) || cr.Status.State == psmdbv1.RestoreStateNew { - log.Info("Waiting for statefulsets to be ready before restore", "ready", sfsReady) - return status, nil - } + if cr.Status.State == psmdbv1.RestoreStateWaiting || status.State == psmdbv1.RestoreStateWaiting { + if err := r.prepareStatefulSetsForPhysicalRestore(ctx, cluster); err != nil { + return status, errors.Wrap(err, "prepare statefulsets for physical restore") + } - if cr.Status.State == psmdbv1.RestoreStateWaiting && sfsReady && cr.Spec.PITR != nil { - rsReady, err := r.checkIfReplsetsAreReadyForPhysicalRestore(ctx, cluster) + sfsReady, err := r.checkIfStatefulSetsAreReadyForPhysicalRestore(ctx, cluster) if err != nil { - return status, errors.Wrap(err, "check if replsets are ready for physical restore") + return status, errors.Wrap(err, "check if statefulsets are ready for physical restore") + } + + if (!sfsReady && cr.Status.State != psmdbv1.RestoreStateRunning) || cr.Status.State == psmdbv1.RestoreStateNew { + log.Info("Waiting for statefulsets to be ready before restore", "ready", sfsReady) + return status, nil } - if !rsReady { - if err := r.prepareReplsetsForPhysicalRestore(ctx, cluster); err != nil { - return status, errors.Wrap(err, "prepare replsets for physical restore") + if sfsReady && cr.Spec.PITR != nil { + rsReady, err := r.checkIfReplsetsAreReadyForPhysicalRestore(ctx, cluster) + if err != nil { + return status, errors.Wrap(err, "check if replsets are ready for physical restore") } - log.Info("Waiting for replsets to be ready before restore", "ready", rsReady) - return status, nil + if !rsReady { + if err := r.prepareReplsetsForPhysicalRestore(ctx, cluster); err != nil { + return status, errors.Wrap(err, "prepare replsets for physical restore") + } + + log.Info("Waiting for replsets to be ready before restore", "ready", rsReady) + return status, nil + } } } @@ -186,154 +191,275 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( return status, nil } - meta := backup.BackupMeta{} + pod := corev1.Pod{} + if err := r.client.Get(ctx, types.NamespacedName{Name: replsets[0].PodName(cluster, 0), Namespace: cluster.Namespace}, &pod); err != nil { + if k8serrors.IsNotFound(err) { + return status, nil + } + return status, errors.Wrap(err, "get pod") + } - err = retry.OnError(retry.DefaultBackoff, func(err error) bool { - return (strings.Contains(err.Error(), "container is not created or running") || - strings.Contains(err.Error(), "error dialing backend: No agent available") || - strings.Contains(err.Error(), "unable to upgrade connection") || - strings.Contains(err.Error(), "unmarshal PBM describe-restore output")) - }, func() error { - stdoutBuf.Reset() - stderrBuf.Reset() + if pod.Spec.Containers[0].Name == naming.ContainerBackupAgent && pod.DeletionTimestamp == nil { + meta := backup.BackupMeta{} + notFound := false - command := []string{ - "/opt/percona/pbm", "describe-restore", cr.Status.PBMname, - "--config", "/etc/pbm/pbm_config.yaml", - "--out", "json", - } + err = retry.OnError(retry.DefaultBackoff, func(err error) bool { + return (strings.Contains(err.Error(), "container is not created or running") || + strings.Contains(err.Error(), "error dialing backend: No agent available") || + strings.Contains(err.Error(), "unable to upgrade connection") || + strings.Contains(err.Error(), "unmarshal PBM describe-restore output")) + }, func() error { + stdoutBuf.Reset() + stderrBuf.Reset() - pod := corev1.Pod{} - if err := r.client.Get(ctx, types.NamespacedName{Name: replsets[0].PodName(cluster, 0), Namespace: cluster.Namespace}, &pod); err != nil { - return errors.Wrap(err, "get pod") + command := []string{ + "/opt/percona/pbm", "describe-restore", cr.Status.PBMname, + "--config", "/etc/pbm/pbm_config.yaml", + "--out", "json", + } + + log.V(1).Info("Check restore status", "command", command, "pod", pod.Name) + + if err := r.clientcmd.Exec(ctx, &pod, "mongod", command, nil, stdoutBuf, stderrBuf, false); err != nil { + return errors.Wrapf(err, "describe restore stderr: %s stdout: %s", stderrBuf.String(), stdoutBuf.String()) + } + + return nil + }) + if err != nil { + return status, err } - log.V(1).Info("Check restore status", "command", command, "pod", pod.Name) + if notFound { + return status, nil + } - if err := r.clientcmd.Exec(ctx, &pod, "mongod", command, nil, stdoutBuf, stderrBuf, false); err != nil { - return errors.Wrapf(err, "describe restore stderr: %s stdout: %s", stderrBuf.String(), stdoutBuf.String()) + if err := json.Unmarshal(stdoutBuf.Bytes(), &meta); err != nil { + return status, errors.Wrap(err, "unmarshal PBM describe-restore output") } - return nil - }) - if err != nil { - return status, err - } + log.V(1).Info("PBM restore status", "status", meta) - if err := json.Unmarshal(stdoutBuf.Bytes(), &meta); err != nil { - return status, errors.Wrap(err, "unmarshal PBM describe-restore output") - } + restoreIsDone := false + switch meta.Status { + case defs.StatusStarting: + for _, rs := range meta.Replsets { + if rs.Status == defs.StatusRunning { + status.State = psmdbv1.RestoreStateRunning + return status, nil + } + } + case defs.StatusError: + status.State = psmdbv1.RestoreStateError + status.Error = meta.Err + case defs.StatusRunning: + status.State = psmdbv1.RestoreStateRunning + case defs.StatusDone: + for _, rs := range meta.Replsets { + if rs.Status == defs.StatusDone { + continue + } - log.V(1).Info("PBM restore status", "status", meta) + log.Info("Waiting replset restore to finish", "replset", rs.Name, "status", rs.Status) - switch meta.Status { - case defs.StatusStarting: - for _, rs := range meta.Replsets { - if rs.Status == defs.StatusRunning { status.State = psmdbv1.RestoreStateRunning return status, nil } - } - case defs.StatusError: - status.State = psmdbv1.RestoreStateError - status.Error = meta.Err - case defs.StatusRunning: - status.State = psmdbv1.RestoreStateRunning - case defs.StatusDone: - for _, rs := range meta.Replsets { - if rs.Status == defs.StatusDone { - continue - } - log.Info("Waiting replset restore to finish", "replset", rs.Name, "status", rs.Status) + // status.State = psmdbv1.RestoreStateReady + restoreIsDone = true + } - status.State = psmdbv1.RestoreStateRunning + if !restoreIsDone { return status, nil } - status.State = psmdbv1.RestoreStateReady + if err := r.iterateOverMongodSts(ctx, cluster, func(s *appsv1.StatefulSet) error { + if err := r.client.Delete(ctx, s); err != nil { + return errors.Wrapf(err, "delete statefulset %s", s) + } + return nil + }); client.IgnoreNotFound(err) != nil { + return status, err + } + return status, nil + } + + finished, err := r.finishPhysicalRestore(ctx, cluster) + if err != nil { + return status, err // TODO: shouldn't return error + } + if !finished { + return status, nil } - if status.State == psmdbv1.RestoreStateReady { - replsets := cluster.Spec.Replsets - if cluster.Spec.Sharding.Enabled { - replsets = append(replsets, cluster.Spec.Sharding.ConfigsvrReplSet) + status.State = psmdbv1.RestoreStateReady + + err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + c := &psmdbv1.PerconaServerMongoDB{} + err := r.client.Get(ctx, types.NamespacedName{Name: cluster.Name, Namespace: cluster.Namespace}, c) + if err != nil { + return err } - for _, rs := range replsets { - stsName := naming.MongodStatefulSetName(cluster, rs) + orig := c.DeepCopy() - log.Info("Deleting statefulset", "statefulset", stsName) + if c.Annotations == nil { + c.Annotations = make(map[string]string) + } + c.Annotations[psmdbv1.AnnotationResyncPBM] = "true" - sts := appsv1.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: stsName, - Namespace: cluster.Namespace, - }, - } + return r.client.Patch(ctx, c, client.MergeFrom(orig)) + }) + if err != nil { + return status, errors.Wrapf(err, "annotate psmdb/%s for PBM resync", cluster.Name) + } - if err := r.client.Delete(ctx, &sts); err != nil { - return status, errors.Wrapf(err, "delete statefulset %s", stsName) - } + return status, nil +} - if rs.NonVoting.Enabled { - stsName := naming.NonVotingStatefulSetName(cluster, rs) +func (r *ReconcilePerconaServerMongoDBRestore) finishPhysicalRestore(ctx context.Context, cluster *api.PerconaServerMongoDB) (bool, error) { + stsIsUpdated := true + if err := r.updateMongodSts(ctx, cluster, func(sts *appsv1.StatefulSet) error { + if sts.Spec.Template.Spec.Containers[0].Name == naming.ContainerBackupAgent { + stsIsUpdated = false + } else if sts.Annotations[psmdbv1.AnnotationRestoreInProgress] != "true" { + stsIsUpdated = false + sts.Annotations[psmdbv1.AnnotationRestoreInProgress] = "true" + } + return nil + }); client.IgnoreNotFound(err) != nil { + return false, errors.Wrap(err, "delete restore in progress annotation") + } + if !stsIsUpdated { + return false, nil + } - log.Info("Deleting statefulset", "statefulset", stsName) + ready := true + err := r.iterateOverMongodSts(ctx, cluster, func(s *appsv1.StatefulSet) error { + if !ready { + return nil + } - sts := appsv1.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: stsName, - Namespace: cluster.Namespace, - }, - } + var err error + ready, err = r.isStatefulSetReady(ctx, cluster, s) + return err + }) + if client.IgnoreNotFound(err) != nil { + return false, err + } + if !ready || k8serrors.IsNotFound(err) { + return false, err + } - if err := r.client.Delete(ctx, &sts); err != nil { - return status, errors.Wrapf(err, "delete statefulset %s", stsName) + wait := false + if err := r.iterateOverMongodSts(ctx, cluster, func(s *appsv1.StatefulSet) error { + if s.Labels[naming.LabelKubernetesComponent] != naming.ComponentMongod { + return nil + } + rs := cluster.Spec.Replset(s.Labels[naming.LabelKubernetesReplset]) + c, err := r.MongoClientWithRole(ctx, cluster, rs, api.RoleClusterAdmin) + if err != nil { + wait = true + + if errors.Is(err, topology.ErrServerSelectionTimeout) && strings.Contains(err.Error(), "ReplicaSetNoPrimary") { + pods, err := r.getReplsetPods(ctx, cluster, rs, s.Labels[naming.LabelKubernetesComponent]) + if err != nil { + return err + } + for _, pod := range pods.Items { + cli, err := r.StandaloneClientWithRole(ctx, cluster, rs, api.RoleClusterAdmin, pod) + if err != nil { + continue + } + defer cli.Disconnect(ctx) + + cfg, err := cli.ReadConfig(ctx) + if err != nil { + return errors.Wrap(err, "read replset config") + } + + if err := cli.WriteConfig(ctx, cfg, true); err != nil { + return errors.Wrap(err, "reconfigure replset") + } } + return nil + } else { + return err } + } + return c.Disconnect(ctx) + }); err != nil { + return false, err + } + if wait { + return false, nil + } + + if err := r.updateMongodSts(ctx, cluster, func(sts *appsv1.StatefulSet) error { + if sts.Annotations[psmdbv1.AnnotationRestoreInProgress] == "true" { + delete(sts.Annotations, psmdbv1.AnnotationRestoreInProgress) + } + return nil + }); err != nil { + return false, errors.Wrap(err, "delete restore in progress annotation") + } - if rs.Arbiter.Enabled { - stsName := naming.ArbiterStatefulSetName(cluster, rs) + return true, nil +} - log.Info("Deleting statefulset", "statefulset", stsName) +func (r *ReconcilePerconaServerMongoDBRestore) iterateOverMongodSts(ctx context.Context, cluster *psmdbv1.PerconaServerMongoDB, itFunc func(s *appsv1.StatefulSet) error) error { + replsets := cluster.Spec.Replsets + if cluster.Spec.Sharding.Enabled { + replsets = append(replsets, cluster.Spec.Sharding.ConfigsvrReplSet) + } - sts := appsv1.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: stsName, - Namespace: cluster.Namespace, - }, - } + var errList []error + for _, rs := range replsets { + stsList := []string{naming.MongodStatefulSetName(cluster, rs)} + if rs.NonVoting.Enabled { + stsList = append(stsList, naming.NonVotingStatefulSetName(cluster, rs)) + } + if rs.NonVoting.Enabled { + stsList = append(stsList, naming.ArbiterStatefulSetName(cluster, rs)) + } - if err := r.client.Delete(ctx, &sts); err != nil { - return status, errors.Wrapf(err, "delete statefulset %s", stsName) - } + var rsErrList []error + for _, sts := range stsList { + s := new(appsv1.StatefulSet) + if err := r.client.Get(ctx, types.NamespacedName{Name: sts, Namespace: cluster.Namespace}, s); err != nil { + return err + } + if err := itFunc(s); err != nil { + rsErrList = append(rsErrList, err) } } - err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { - c := &psmdbv1.PerconaServerMongoDB{} - err := r.client.Get(ctx, types.NamespacedName{Name: cluster.Name, Namespace: cluster.Namespace}, c) - if err != nil { + if len(rsErrList) > 0 { + errList = append(errList, errors.Wrapf(stdError.Join(rsErrList...), "failed to edit statefulsets for replset %s", rs.Name)) + } + } + if len(errList) > 0 { + return stdError.Join(errList...) + } + return nil +} + +func (r *ReconcilePerconaServerMongoDBRestore) updateMongodSts(ctx context.Context, cluster *psmdbv1.PerconaServerMongoDB, updateFunc func(s *appsv1.StatefulSet) error) error { + return r.iterateOverMongodSts(ctx, cluster, func(s *appsv1.StatefulSet) error { + return retry.RetryOnConflict(retry.DefaultBackoff, func() error { + sts := new(appsv1.StatefulSet) + if err := r.client.Get(ctx, client.ObjectKeyFromObject(s), sts); err != nil { return err } - orig := c.DeepCopy() - - if c.Annotations == nil { - c.Annotations = make(map[string]string) + if err := updateFunc(sts); err != nil { + return err } - c.Annotations[psmdbv1.AnnotationResyncPBM] = "true" - return r.client.Patch(ctx, c, client.MergeFrom(orig)) + return r.client.Update(ctx, sts) }) - if err != nil { - return status, errors.Wrapf(err, "annotate psmdb/%s for PBM resync", cluster.Name) - } - - } - - return status, nil + }) } // updateStatefulSetForPhysicalRestore updates the StatefulSet to prepare it for a physical restore of PerconaServerMongoDB. @@ -470,84 +596,28 @@ func (r *ReconcilePerconaServerMongoDBRestore) updateStatefulSetForPhysicalResto func (r *ReconcilePerconaServerMongoDBRestore) prepareStatefulSetsForPhysicalRestore(ctx context.Context, cluster *psmdbv1.PerconaServerMongoDB) error { log := logf.FromContext(ctx) - replsets := cluster.Spec.Replsets - if cluster.Spec.Sharding.Enabled { - replsets = append(replsets, cluster.Spec.Sharding.ConfigsvrReplSet) - } - - for _, rs := range replsets { - stsName := naming.MongodStatefulSetName(cluster, rs) - - sts := appsv1.StatefulSet{} - nn := types.NamespacedName{Namespace: cluster.Namespace, Name: stsName} - err := r.client.Get(ctx, nn, &sts) - if err != nil { - return err - } - + if err := r.updateMongodSts(ctx, cluster, func(sts *appsv1.StatefulSet) error { _, ok := sts.Annotations[psmdbv1.AnnotationRestoreInProgress] if ok { - continue - } - - log.Info("Preparing statefulset for physical restore", "name", stsName) - - err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - return r.updateStatefulSetForPhysicalRestore(ctx, cluster, types.NamespacedName{Namespace: cluster.Namespace, Name: stsName}) - }) - if err != nil { - return errors.Wrapf(err, "prepare statefulset %s for physical restore", stsName) + return nil } + log.Info("Preparing statefulset for physical restore", "name", sts.Name) - if rs.NonVoting.Enabled { - stsName := naming.NonVotingStatefulSetName(cluster, rs) - nn := types.NamespacedName{Namespace: cluster.Namespace, Name: stsName} + if sts.Labels[naming.LabelKubernetesComponent] == naming.ComponentArbiter { + zero := int32(0) - log.Info("Preparing statefulset for physical restore", "name", stsName) + sts.Spec.Replicas = &zero - err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - return r.updateStatefulSetForPhysicalRestore(ctx, cluster, nn) - }) - if err != nil { - return errors.Wrapf(err, "prepare statefulset %s for physical restore", stsName) + if sts.Annotations == nil { + sts.Annotations = make(map[string]string) } + sts.Annotations[psmdbv1.AnnotationRestoreInProgress] = "true" + return nil } - if rs.Arbiter.Enabled { - stsName := naming.ArbiterStatefulSetName(cluster, rs) - nn := types.NamespacedName{Namespace: cluster.Namespace, Name: stsName} - - log.Info("Preparing statefulset for physical restore", "name", stsName) - - err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - sts := appsv1.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: stsName, - Namespace: cluster.Namespace, - }, - } - - err := r.client.Get(ctx, nn, &sts) - if err != nil { - return err - } - - orig := sts.DeepCopy() - zero := int32(0) - - sts.Spec.Replicas = &zero - - if sts.Annotations == nil { - sts.Annotations = make(map[string]string) - } - sts.Annotations[psmdbv1.AnnotationRestoreInProgress] = "true" - - return r.client.Patch(ctx, &sts, client.MergeFrom(orig)) - }) - if err != nil { - return errors.Wrapf(err, "prepare statefulset %s for physical restore", stsName) - } - } + return r.updateStatefulSetForPhysicalRestore(ctx, cluster, client.ObjectKeyFromObject(sts)) + }); err != nil { + return errors.Wrap(err, "update replset sts") } return nil @@ -811,71 +881,68 @@ func (r *ReconcilePerconaServerMongoDBRestore) checkIfStatefulSetsAreReadyForPhy if cluster.Spec.Sharding.Enabled { replsets = append(replsets, cluster.Spec.Sharding.ConfigsvrReplSet) } - - for _, rs := range replsets { - ready, err := r.checkStatefulSetForPhysicalRestore(ctx, cluster, rs, naming.ComponentMongod) - if err != nil { - return false, errors.Wrapf(err, "check %s %s statefulset", rs.Name, naming.ComponentMongod) + ready := true + if err := r.iterateOverMongodSts(ctx, cluster, func(s *appsv1.StatefulSet) error { + if s.Labels[naming.LabelKubernetesComponent] == naming.ComponentArbiter || ready == false { + return nil } - - if !ready { - return false, nil + var err error + ready, err = r.checkStatefulSetForPhysicalRestore(ctx, cluster, s) + if err != nil { + return errors.Wrapf(err, "check %s %s statefulset", s.Labels[naming.LabelKubernetesReplset], s.Labels[naming.LabelKubernetesComponent]) } + return nil + }); err != nil { + return false, err + } + return ready, nil +} - if rs.NonVoting.Enabled { - ready, err := r.checkStatefulSetForPhysicalRestore(ctx, cluster, rs, naming.ComponentNonVoting) - if err != nil { - return false, errors.Wrapf(err, "check %s %s statefulset", rs.Name, naming.ComponentNonVoting) - } +func (r *ReconcilePerconaServerMongoDBRestore) isStatefulSetReady(ctx context.Context, cluster *psmdbv1.PerconaServerMongoDB, sts *appsv1.StatefulSet) (bool, error) { + if sts.Status.Replicas != sts.Status.ReadyReplicas { + return false, nil + } - if !ready { - return false, nil - } + rs := cluster.Spec.Replset(sts.Labels[naming.LabelKubernetesReplset]) + podList, err := r.getReplsetPods(ctx, cluster, rs, sts.Labels[naming.LabelKubernetesComponent]) + if err != nil { + return false, errors.Wrapf(err, "get replset %s pods", sts.Labels[naming.LabelKubernetesReplset]) + } + for _, pod := range podList.Items { + if pod.ObjectMeta.Labels["controller-revision-hash"] != sts.Status.UpdateRevision { + return false, nil } } - return true, nil } func (r *ReconcilePerconaServerMongoDBRestore) checkStatefulSetForPhysicalRestore( ctx context.Context, cluster *psmdbv1.PerconaServerMongoDB, - rs *psmdbv1.ReplsetSpec, - component string, + sts *appsv1.StatefulSet, ) (bool, error) { log := logf.FromContext(ctx) - stsName := naming.MongodStatefulSetName(cluster, rs) - if component == naming.ComponentNonVoting { - stsName = naming.NonVotingStatefulSetName(cluster, rs) - } - - sts := appsv1.StatefulSet{} - nn := types.NamespacedName{Namespace: cluster.Namespace, Name: stsName} - err := r.client.Get(ctx, nn, &sts) - if err != nil { - return false, err - } - _, ok := sts.Annotations[psmdbv1.AnnotationRestoreInProgress] if !ok { return false, nil } - if sts.Status.Replicas != sts.Status.ReadyReplicas { - return false, nil + ready, err := r.isStatefulSetReady(ctx, cluster, sts) + if err != nil { + return false, err + } + if !ready { + return ready, nil } - podList, err := r.getReplsetPods(ctx, cluster, rs, component) + rs := cluster.Spec.Replset(sts.Labels[naming.LabelKubernetesReplset]) + podList, err := r.getReplsetPods(ctx, cluster, rs, sts.Labels[naming.LabelKubernetesComponent]) if err != nil { - return false, errors.Wrapf(err, "get replset %s pods", rs.Name) + return false, errors.Wrapf(err, "get replset %s pods", sts.Labels[naming.LabelKubernetesReplset]) } for _, pod := range podList.Items { - if pod.ObjectMeta.Labels["controller-revision-hash"] != sts.Status.UpdateRevision { - return false, nil - } - for _, c := range pod.Spec.Containers { if c.Name == naming.ContainerBackupAgent { return false, nil @@ -885,7 +952,7 @@ func (r *ReconcilePerconaServerMongoDBRestore) checkStatefulSetForPhysicalRestor log.V(1).Info("Pod is ready for physical restore", "pod", pod.Name) } - log.V(1).Info("Statefulset is ready for physical restore", "sts", sts.Name, "replset", rs.Name) + log.V(1).Info("Statefulset is ready for physical restore", "sts", sts.Name, "replset", sts.Labels[naming.LabelKubernetesReplset]) return true, nil } diff --git a/pkg/controller/perconaservermongodbrestore/validate.go b/pkg/controller/perconaservermongodbrestore/validate.go index 5516195d68..dd9bbf29c4 100644 --- a/pkg/controller/perconaservermongodbrestore/validate.go +++ b/pkg/controller/perconaservermongodbrestore/validate.go @@ -11,9 +11,7 @@ import ( "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" ) -var ( - errWaitingPBM = errors.New("waiting for pbm-agent") -) +var errWaitingPBM = errors.New("waiting for pbm-agent") func (r *ReconcilePerconaServerMongoDBRestore) validate(ctx context.Context, cr *psmdbv1.PerconaServerMongoDBRestore, cluster *psmdbv1.PerconaServerMongoDB) error { if cluster.Spec.Unmanaged { @@ -34,7 +32,7 @@ func (r *ReconcilePerconaServerMongoDBRestore) validate(ctx context.Context, cr return errors.Wrap(err, "get storage") } - pbmc, err := r.newPBMFunc(ctx, r.client, cluster) + pbmc, err := r.NewPBM(ctx, cluster) if err != nil { return errWaitingPBM } diff --git a/pkg/controller/perconaservermongodbrestore/validate_test.go b/pkg/controller/perconaservermongodbrestore/validate_test.go index 68905e1a7a..b4f826d044 100644 --- a/pkg/controller/perconaservermongodbrestore/validate_test.go +++ b/pkg/controller/perconaservermongodbrestore/validate_test.go @@ -11,6 +11,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" fakeBackup "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup/fake" ) @@ -166,8 +167,7 @@ func fakeReconciler(objs ...client.Object) *ReconcilePerconaServerMongoDBRestore cl := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).WithStatusSubresource(objs...).Build() return &ReconcilePerconaServerMongoDBRestore{ - client: cl, - scheme: s, - newPBMFunc: fakeBackup.NewPBM, + CommonReconciler: common.New(cl, s, fakeBackup.NewPBM, nil), + client: cl, } } diff --git a/pkg/psmdb/client.go b/pkg/psmdb/client.go index 3c093cf8f4..d7f12d9e81 100644 --- a/pkg/psmdb/client.go +++ b/pkg/psmdb/client.go @@ -62,7 +62,7 @@ func MongoClient(ctx context.Context, k8sClient client.Client, cr *api.PerconaSe return mongo.Dial(conf) } -func MongosClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaServerMongoDB, c Credentials) (mongo.Client, error) { +func mongosClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaServerMongoDB, c Credentials) (mongo.Client, error) { hosts, err := GetMongosAddrs(ctx, k8sclient, cr, true) if err != nil { return nil, errors.Wrap(err, "get mongos addrs") @@ -85,7 +85,7 @@ func MongosClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaS return mongo.Dial(&conf) } -func StandaloneClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaServerMongoDB, c Credentials, host string, tlsEnabled bool) (mongo.Client, error) { +func standaloneClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaServerMongoDB, c Credentials, host string, tlsEnabled bool) (mongo.Client, error) { conf := mongo.Config{ Hosts: []string{host}, Username: c.Username, diff --git a/pkg/psmdb/provider.go b/pkg/psmdb/provider.go new file mode 100644 index 0000000000..fba07e67c2 --- /dev/null +++ b/pkg/psmdb/provider.go @@ -0,0 +1,94 @@ +package psmdb + +import ( + "context" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo" +) + +type MongoClientProvider interface { + Mongo(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) + Mongos(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (mongo.Client, error) + Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole, host string, tlsEnabled bool) (mongo.Client, error) +} + +type mongoClientProvider struct { + k8sclient client.Client +} + +func NewProvider(c client.Client) *mongoClientProvider { + return &mongoClientProvider{k8sclient: c} +} + +func (p *mongoClientProvider) Mongo(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) { + c, err := GetCredentials(ctx, p.k8sclient, cr, role) + if err != nil { + return nil, errors.Wrap(err, "failed to get credentials") + } + + return MongoClient(ctx, p.k8sclient, cr, rs, c) +} + +func (p *mongoClientProvider) Mongos(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (mongo.Client, error) { + c, err := GetCredentials(ctx, p.k8sclient, cr, role) + if err != nil { + return nil, errors.Wrap(err, "failed to get credentials") + } + + return mongosClient(ctx, p.k8sclient, cr, c) +} + +func (p *mongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole, host string, tlsEnabled bool) (mongo.Client, error) { + c, err := GetCredentials(ctx, p.k8sclient, cr, role) + if err != nil { + return nil, errors.Wrap(err, "failed to get credentials") + } + + return standaloneClient(ctx, p.k8sclient, cr, c, host, tlsEnabled) +} + +func getUserSecret(ctx context.Context, cl client.Reader, cr *api.PerconaServerMongoDB, name string) (corev1.Secret, error) { + secrets := corev1.Secret{} + err := cl.Get(ctx, types.NamespacedName{Name: name, Namespace: cr.Namespace}, &secrets) + return secrets, errors.Wrap(err, "get user secrets") +} + +func GetCredentials(ctx context.Context, cl client.Reader, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (Credentials, error) { + creds := Credentials{} + usersSecret, err := getUserSecret(ctx, cl, cr, api.UserSecretName(cr)) + if err != nil { + return creds, errors.Wrap(err, "failed to get user secret") + } + + switch role { + case api.RoleDatabaseAdmin: + creds.Username = string(usersSecret.Data[api.EnvMongoDBDatabaseAdminUser]) + creds.Password = string(usersSecret.Data[api.EnvMongoDBDatabaseAdminPassword]) + case api.RoleClusterAdmin: + creds.Username = string(usersSecret.Data[api.EnvMongoDBClusterAdminUser]) + creds.Password = string(usersSecret.Data[api.EnvMongoDBClusterAdminPassword]) + case api.RoleUserAdmin: + creds.Username = string(usersSecret.Data[api.EnvMongoDBUserAdminUser]) + creds.Password = string(usersSecret.Data[api.EnvMongoDBUserAdminPassword]) + case api.RoleClusterMonitor: + creds.Username = string(usersSecret.Data[api.EnvMongoDBClusterMonitorUser]) + creds.Password = string(usersSecret.Data[api.EnvMongoDBClusterMonitorPassword]) + case api.RoleBackup: + creds.Username = string(usersSecret.Data[api.EnvMongoDBBackupUser]) + creds.Password = string(usersSecret.Data[api.EnvMongoDBBackupPassword]) + default: + return creds, errors.Errorf("not implemented for role: %s", role) + } + + if creds.Username == "" || creds.Password == "" { + return creds, errors.Errorf("can't find credentials for role %s", role) + } + + return creds, nil +} From 49cc0447ec7a5d7a8a904675e7b7451f2a2aa89b Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Mon, 19 May 2025 09:51:11 +0300 Subject: [PATCH 02/10] remove unused comment --- pkg/controller/common/common.go | 46 --------------------------------- 1 file changed, 46 deletions(-) diff --git a/pkg/controller/common/common.go b/pkg/controller/common/common.go index 7d5af3ee5d..7fbe7bfc23 100644 --- a/pkg/controller/common/common.go +++ b/pkg/controller/common/common.go @@ -68,49 +68,3 @@ func (r *CommonReconciler) StandaloneClientWithRole(ctx context.Context, cr *api } return r.getMongoClientProvider().Standalone(ctx, cr, role, host, cr.TLSEnabled()) } - -/* -// ReconcilePerconaServerMongoDB reconciles a PerconaServerMongoDB object -type ReconcilePerconaServerMongoDB struct { - // This client, initialized using mgr.Client() above, is a split client - // that reads objects from the cache and writes to the apiserver - client client.Client - scheme *runtime.Scheme - restConfig *rest.Config - - crons CronRegistry - clientcmd *clientcmd.Client - serverVersion *version.ServerVersion - reconcileIn time.Duration - mongoClientProvider psmdb.MongoClientProvider - - newCertManagerCtrlFunc tls.NewCertManagerControllerFunc - - newPBM backup.NewPBMFunc - - initImage string - - lockers lockStore -} - -// ReconcilePerconaServerMongoDBRestore reconciles a PerconaServerMongoDBRestore object -type ReconcilePerconaServerMongoDBRestore struct { - // This client, initialized using mgr.Client() above, is a split client - // that reads objects from the cache and writes to the apiserver - client client.Client - scheme *runtime.Scheme - clientcmd *clientcmd.Client - - newPBMFunc backup.NewPBMFunc -} -// ReconcilePerconaServerMongoDBBackup reconciles a PerconaServerMongoDBBackup object -type ReconcilePerconaServerMongoDBBackup struct { - // This client, initialized using mgr.Client() above, is a split client - // that reads objects from the cache and writes to the apiserver - client client.Client - scheme *runtime.Scheme - clientcmd *clientcmd.Client - - newPBMFunc backup.NewPBMFunc -} -*/ From 19de9e6dc89ef1ee32a6136bd984ffe0d14d83e5 Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Mon, 19 May 2025 12:30:43 +0300 Subject: [PATCH 03/10] fix lint --- .../perconaservermongodbrestore/physical.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pkg/controller/perconaservermongodbrestore/physical.go b/pkg/controller/perconaservermongodbrestore/physical.go index 7cd0bd2fe8..62565848f0 100644 --- a/pkg/controller/perconaservermongodbrestore/physical.go +++ b/pkg/controller/perconaservermongodbrestore/physical.go @@ -367,12 +367,12 @@ func (r *ReconcilePerconaServerMongoDBRestore) finishPhysicalRestore(ctx context if err != nil { return err } - for _, pod := range pods.Items { + updateConfig := func(pod corev1.Pod) error { cli, err := r.StandaloneClientWithRole(ctx, cluster, rs, api.RoleClusterAdmin, pod) if err != nil { - continue + return nil } - defer cli.Disconnect(ctx) + defer func() { _ = cli.Disconnect(ctx) }() cfg, err := cli.ReadConfig(ctx) if err != nil { @@ -382,6 +382,12 @@ func (r *ReconcilePerconaServerMongoDBRestore) finishPhysicalRestore(ctx context if err := cli.WriteConfig(ctx, cfg, true); err != nil { return errors.Wrap(err, "reconfigure replset") } + return nil + } + for _, pod := range pods.Items { + if err := updateConfig(pod); err != nil { + return err + } } return nil } else { @@ -883,7 +889,7 @@ func (r *ReconcilePerconaServerMongoDBRestore) checkIfStatefulSetsAreReadyForPhy } ready := true if err := r.iterateOverMongodSts(ctx, cluster, func(s *appsv1.StatefulSet) error { - if s.Labels[naming.LabelKubernetesComponent] == naming.ComponentArbiter || ready == false { + if s.Labels[naming.LabelKubernetesComponent] == naming.ComponentArbiter || !ready { return nil } var err error @@ -909,7 +915,7 @@ func (r *ReconcilePerconaServerMongoDBRestore) isStatefulSetReady(ctx context.Co return false, errors.Wrapf(err, "get replset %s pods", sts.Labels[naming.LabelKubernetesReplset]) } for _, pod := range podList.Items { - if pod.ObjectMeta.Labels["controller-revision-hash"] != sts.Status.UpdateRevision { + if pod.Labels["controller-revision-hash"] != sts.Status.UpdateRevision { return false, nil } } From 9bf2482619d20baa3636cf361fe006f019b8684b Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Tue, 20 May 2025 17:01:46 +0300 Subject: [PATCH 04/10] remove common reconciler --- pkg/controller/common/common.go | 70 ------------------- pkg/controller/perconaservermongodb/backup.go | 2 +- .../perconaservermongodb/balancer.go | 4 +- .../perconaservermongodb/connections_test.go | 11 ++- .../perconaservermongodb/custom_users.go | 4 +- pkg/controller/perconaservermongodb/fcv.go | 6 +- .../perconaservermongodb/finalizers.go | 2 +- pkg/controller/perconaservermongodb/mgo.go | 12 ++-- .../perconaservermongodb/psmdb_controller.go | 17 +++-- .../perconaservermongodb/service.go | 8 +-- pkg/controller/perconaservermongodb/smart.go | 12 ++-- pkg/controller/perconaservermongodb/ssl.go | 12 ++-- .../perconaservermongodb/statefulset.go | 2 +- .../perconaservermongodb/status_test.go | 4 +- .../perconaservermongodb/suite_test.go | 4 +- pkg/controller/perconaservermongodb/users.go | 2 +- .../perconaservermongodb/version.go | 2 +- .../perconaservermongodb/version_test.go | 3 +- .../perconaservermongodbbackup/backup.go | 2 +- .../perconaservermongodbbackup_controller.go | 15 ++-- .../perconaservermongodbrestore_controller.go | 14 ++-- .../perconaservermongodbrestore/physical.go | 4 +- .../perconaservermongodbrestore/validate.go | 2 +- .../validate_test.go | 6 +- pkg/psmdb/provider.go | 34 +++++++-- 25 files changed, 108 insertions(+), 146 deletions(-) delete mode 100644 pkg/controller/common/common.go diff --git a/pkg/controller/common/common.go b/pkg/controller/common/common.go deleted file mode 100644 index 7fbe7bfc23..0000000000 --- a/pkg/controller/common/common.go +++ /dev/null @@ -1,70 +0,0 @@ -package common - -import ( - "context" - - "github.com/pkg/errors" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" - "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" - "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo" -) - -func New(client client.Client, scheme *runtime.Scheme, newPBMFunc backup.NewPBMFunc, mongoClientProvider psmdb.MongoClientProvider) CommonReconciler { - return CommonReconciler{ - client: client, - scheme: scheme, - newPBMFunc: newPBMFunc, - mongoClientProvider: mongoClientProvider, - } -} - -type CommonReconciler struct { - client client.Client - scheme *runtime.Scheme - newPBMFunc backup.NewPBMFunc - mongoClientProvider psmdb.MongoClientProvider -} - -func (r *CommonReconciler) Client() client.Client { - return r.client -} - -func (r *CommonReconciler) Scheme() *runtime.Scheme { - return r.scheme -} - -func (r *CommonReconciler) NewPBM(ctx context.Context, cluster *api.PerconaServerMongoDB) (backup.PBM, error) { - return r.newPBMFunc(ctx, r.client, cluster) -} - -func (r *CommonReconciler) NewPBMFunc() backup.NewPBMFunc { - return r.newPBMFunc -} - -func (r *CommonReconciler) getMongoClientProvider() psmdb.MongoClientProvider { - if r.mongoClientProvider == nil { - return psmdb.NewProvider(r.client) - } - return r.mongoClientProvider -} - -func (r *CommonReconciler) MongoClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) { - return r.getMongoClientProvider().Mongo(ctx, cr, rs, role) -} - -func (r *CommonReconciler) MongosClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (mongo.Client, error) { - return r.getMongoClientProvider().Mongos(ctx, cr, role) -} - -func (r *CommonReconciler) StandaloneClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole, pod corev1.Pod) (mongo.Client, error) { - host, err := psmdb.MongoHost(ctx, r.client, cr, cr.Spec.ClusterServiceDNSMode, rs, rs.Expose.Enabled, pod) - if err != nil { - return nil, errors.Wrap(err, "failed to get mongo host") - } - return r.getMongoClientProvider().Standalone(ctx, cr, role, host, cr.TLSEnabled()) -} diff --git a/pkg/controller/perconaservermongodb/backup.go b/pkg/controller/perconaservermongodb/backup.go index b9cb581539..85c2c6e2e3 100644 --- a/pkg/controller/perconaservermongodb/backup.go +++ b/pkg/controller/perconaservermongodb/backup.go @@ -60,7 +60,7 @@ func (r *ReconcilePerconaServerMongoDB) createOrUpdateBackupTask(ctx context.Con if err != nil { return errors.Wrap(err, "can't create job") } - err = setControllerReference(cr, &cjob, r.Scheme()) + err = setControllerReference(cr, &cjob, r.scheme) if err != nil { return errors.Wrapf(err, "set owner reference for backup task %s", cjob.Name) } diff --git a/pkg/controller/perconaservermongodb/balancer.go b/pkg/controller/perconaservermongodb/balancer.go index 8b1c85019b..c5ca9be22c 100644 --- a/pkg/controller/perconaservermongodb/balancer.go +++ b/pkg/controller/perconaservermongodb/balancer.go @@ -85,7 +85,7 @@ func (r *ReconcilePerconaServerMongoDB) enableBalancerIfNeeded(ctx context.Conte } } - mongosSession, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + mongosSession, err := r.MongoClient().Mongos(ctx, cr, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "failed to get mongos connection") } @@ -141,7 +141,7 @@ func (r *ReconcilePerconaServerMongoDB) disableBalancer(ctx context.Context, cr return errors.Wrapf(err, "get mongos statefulset %s", msSts.Name) } - mongosSession, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + mongosSession, err := r.MongoClient().Mongos(ctx, cr, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "failed to get mongos connection") } diff --git a/pkg/controller/perconaservermongodb/connections_test.go b/pkg/controller/perconaservermongodb/connections_test.go index 93531c3e55..c36478c024 100644 --- a/pkg/controller/perconaservermongodb/connections_test.go +++ b/pkg/controller/perconaservermongodb/connections_test.go @@ -19,7 +19,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo" @@ -159,7 +158,7 @@ func TestConnectionLeaks(t *testing.T) { connectionCount := new(int) r := buildFakeClient(obj...) - r.CommonReconciler = common.New(r.Client(), r.Scheme(), r.NewPBMFunc(), &fakeMongoClientProvider{pods: rsPods, cr: cr, connectionCount: connectionCount}) + r.MongoProviderBase = psmdb.NewProviderBase(r.client, &fakeMongoClientProvider{pods: rsPods, cr: cr, connectionCount: connectionCount}) r.serverVersion = &version.ServerVersion{Platform: version.PlatformKubernetes} r.crons = NewCronRegistry() @@ -396,18 +395,18 @@ func (g *fakeMongoClientProvider) Mongos(ctx context.Context, cr *api.PerconaSer return &fakeMongoClient{pods: g.pods, cr: g.cr, connectionCount: g.connectionCount, Client: fakeClient}, nil } -func (g *fakeMongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole, host string, tlsEnabled bool) (mongo.Client, error) { +func (g *fakeMongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole, pod corev1.Pod) (mongo.Client, error) { *g.connectionCount++ fakeClient := mongoFake.NewClient() - return &fakeMongoClient{pods: g.pods, cr: g.cr, connectionCount: g.connectionCount, Client: fakeClient, host: host}, nil + return &fakeMongoClient{pods: g.pods, cr: g.cr, connectionCount: g.connectionCount, Client: fakeClient, pod: &pod}, nil } type fakeMongoClient struct { pods []client.Object cr *api.PerconaServerMongoDB connectionCount *int - host string + pod *corev1.Pod mongo.Client } @@ -523,7 +522,7 @@ func (c *fakeMongoClient) IsMaster(ctx context.Context) (*mongo.IsMasterResp, er if err := c.cr.CheckNSetDefaults(ctx, version.PlatformKubernetes); err != nil { return nil, err } - if c.host == psmdb.GetAddr(c.cr, c.pods[0].GetName(), c.cr.Spec.Replsets[0].Name, c.cr.Spec.Replsets[0].GetPort()) { + if c.pod.GetName() == c.pods[0].GetName() { isMaster = true } return &mongo.IsMasterResp{ diff --git a/pkg/controller/perconaservermongodb/custom_users.go b/pkg/controller/perconaservermongodb/custom_users.go index f7001e01f9..38795df9f1 100644 --- a/pkg/controller/perconaservermongodb/custom_users.go +++ b/pkg/controller/perconaservermongodb/custom_users.go @@ -35,9 +35,9 @@ func (r *ReconcilePerconaServerMongoDB) reconcileCustomUsers(ctx context.Context var err error var mongoCli mongo.Client if cr.Spec.Sharding.Enabled { - mongoCli, err = r.MongosClientWithRole(ctx, cr, api.RoleUserAdmin) + mongoCli, err = r.MongoClient().Mongos(ctx, cr, api.RoleUserAdmin) } else { - mongoCli, err = r.MongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleUserAdmin) + mongoCli, err = r.MongoClient().Mongo(ctx, cr, cr.Spec.Replsets[0], api.RoleUserAdmin) } if err != nil { return errors.Wrap(err, "failed to get mongo client") diff --git a/pkg/controller/perconaservermongodb/fcv.go b/pkg/controller/perconaservermongodb/fcv.go index cb71e5708c..95fef67fd3 100644 --- a/pkg/controller/perconaservermongodb/fcv.go +++ b/pkg/controller/perconaservermongodb/fcv.go @@ -12,7 +12,7 @@ import ( ) func (r *ReconcilePerconaServerMongoDB) getFCV(ctx context.Context, cr *api.PerconaServerMongoDB) (string, error) { - c, err := r.MongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleClusterAdmin) + c, err := r.MongoClient().Mongo(ctx, cr, cr.Spec.Replsets[0], api.RoleClusterAdmin) if err != nil { return "", errors.Wrap(err, "failed to get connection") } @@ -40,9 +40,9 @@ func (r *ReconcilePerconaServerMongoDB) setFCV(ctx context.Context, cr *api.Perc var connErr error if cr.Spec.Sharding.Enabled { - cli, connErr = r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + cli, connErr = r.MongoClient().Mongos(ctx, cr, api.RoleClusterAdmin) } else { - cli, connErr = r.MongoClientWithRole(ctx, cr, cr.Spec.Replsets[0], api.RoleClusterAdmin) + cli, connErr = r.MongoClient().Mongo(ctx, cr, cr.Spec.Replsets[0], api.RoleClusterAdmin) } if connErr != nil { diff --git a/pkg/controller/perconaservermongodb/finalizers.go b/pkg/controller/perconaservermongodb/finalizers.go index c1d003d0f8..1419a326ec 100644 --- a/pkg/controller/perconaservermongodb/finalizers.go +++ b/pkg/controller/perconaservermongodb/finalizers.go @@ -85,7 +85,7 @@ func (r *ReconcilePerconaServerMongoDB) checkFinalizers(ctx context.Context, cr } func (r *ReconcilePerconaServerMongoDB) deleteAllPITRChunks(ctx context.Context, cr *api.PerconaServerMongoDB) error { - pbmc, err := r.NewPBM(ctx, cr) + pbmc, err := r.newPBMFunc(ctx, r.client, cr) if err != nil { return errors.Wrap(err, "new pbm") } diff --git a/pkg/controller/perconaservermongodb/mgo.go b/pkg/controller/perconaservermongodb/mgo.go index d5548fca57..34749c788d 100644 --- a/pkg/controller/perconaservermongodb/mgo.go +++ b/pkg/controller/perconaservermongodb/mgo.go @@ -95,7 +95,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileCluster(ctx context.Context, cr } } - cli, err := r.MongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) + cli, err := r.MongoClient().Mongo(ctx, cr, replset, api.RoleClusterAdmin) if err != nil { if cr.Spec.Unmanaged { return api.AppStateInit, nil, nil @@ -193,7 +193,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileCluster(ctx context.Context, cr replset.ClusterRole == api.ClusterRoleShardSvr && len(mongosPods) > 0 && cr.Spec.Sharding.Mongos.Size > 0 { - mongosSession, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + mongosSession, err := r.MongoClient().Mongos(ctx, cr, api.RoleClusterAdmin) if err != nil { return api.AppStateError, nil, errors.Wrap(err, "failed to get mongos connection") } @@ -571,7 +571,7 @@ func (r *ReconcilePerconaServerMongoDB) removeRSFromShard(ctx context.Context, c return nil } - cli, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + cli, err := r.MongoClient().Mongos(ctx, cr, api.RoleClusterAdmin) if err != nil { return errors.Errorf("failed to get mongos connection: %v", err) } @@ -621,7 +621,7 @@ func (r *ReconcilePerconaServerMongoDB) handleRsAddToShard(ctx context.Context, return errors.Wrapf(err, "get rsPod %s host", rspod.Name) } - cli, err := r.MongosClientWithRole(ctx, cr, api.RoleClusterAdmin) + cli, err := r.MongoClient().Mongos(ctx, cr, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "failed to get mongos client") } @@ -757,7 +757,7 @@ func (r *ReconcilePerconaServerMongoDB) handleReplicaSetNoPrimary(ctx context.Co } log.Info("Connecting to pod", "pod", pod.Name, "user", api.RoleClusterAdmin) - cli, err := r.StandaloneClientWithRole(ctx, cr, replset, api.RoleClusterAdmin, pod) + cli, err := r.MongoClient().Standalone(ctx, cr, replset, api.RoleClusterAdmin, pod) if err != nil { return errors.Wrap(err, "get standalone mongo client") } @@ -922,7 +922,7 @@ func compareRoles(x []mongo.Role, y []mongo.Role) bool { func (r *ReconcilePerconaServerMongoDB) createOrUpdateSystemUsers(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.ReplsetSpec) error { log := logf.FromContext(ctx) - cli, err := r.MongoClientWithRole(ctx, cr, replset, api.RoleUserAdmin) + cli, err := r.MongoClient().Mongo(ctx, cr, replset, api.RoleUserAdmin) if err != nil { return errors.Wrap(err, "failed to get mongo client") } diff --git a/pkg/controller/perconaservermongodb/psmdb_controller.go b/pkg/controller/perconaservermongodb/psmdb_controller.go index 23d0e95fd1..f2c262fa79 100644 --- a/pkg/controller/perconaservermongodb/psmdb_controller.go +++ b/pkg/controller/perconaservermongodb/psmdb_controller.go @@ -88,8 +88,9 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) { } return &ReconcilePerconaServerMongoDB{ - CommonReconciler: common.New(client, mgr.GetScheme(), backup.NewPBM, nil), client: client, + scheme: client.Scheme(), + newPBMFunc: backup.NewPBM, serverVersion: sv, reconcileIn: time.Second * 5, crons: NewCronRegistry(), @@ -172,9 +173,11 @@ func NewCronRegistry() CronRegistry { // ReconcilePerconaServerMongoDB reconciles a PerconaServerMongoDB object type ReconcilePerconaServerMongoDB struct { common.CommonReconciler + psmdb.MongoProviderBase // This client, initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver client client.Client + scheme *runtime.Scheme restConfig *rest.Config crons CronRegistry @@ -182,6 +185,8 @@ type ReconcilePerconaServerMongoDB struct { serverVersion *version.ServerVersion reconcileIn time.Duration + newPBMFunc backup.NewPBMFunc + newCertManagerCtrlFunc tls.NewCertManagerControllerFunc initImage string @@ -841,7 +846,7 @@ func (r *ReconcilePerconaServerMongoDB) checkIfUserDataExistInRS(ctx context.Con return errors.Wrap(err, "failed to set port") } - mc, err := r.MongoClientWithRole(ctx, cr, rs, api.RoleClusterAdmin) + mc, err := r.MongoClient().Mongo(ctx, cr, rs, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "dial:") } @@ -884,7 +889,7 @@ func (r *ReconcilePerconaServerMongoDB) ensureSecurityKey(ctx context.Context, c if err != nil && k8serrors.IsNotFound(err) { created = true if setOwner { - err = setControllerReference(cr, key, r.Scheme()) + err = setControllerReference(cr, key, r.scheme) if err != nil { return false, errors.Wrap(err, "set owner ref") } @@ -1182,7 +1187,7 @@ func deleteConfigMapIfExists(ctx context.Context, cl client.Client, cr *api.Perc } func (r *ReconcilePerconaServerMongoDB) createOrUpdateConfigMap(ctx context.Context, cr *api.PerconaServerMongoDB, configMap *corev1.ConfigMap) error { - err := setControllerReference(cr, configMap, r.Scheme()) + err := setControllerReference(cr, configMap, r.scheme) if err != nil { return errors.Wrapf(err, "failed to set controller ref for config map %s", configMap.Name) } @@ -1261,7 +1266,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileMongosStatefulset(ctx context.C } sts := psmdb.MongosStatefulset(cr) - err = setControllerReference(cr, sts, r.Scheme()) + err = setControllerReference(cr, sts, r.scheme) if err != nil { return errors.Wrapf(err, "set owner ref for statefulset %s", sts.Name) } @@ -1488,7 +1493,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcilePDB(ctx context.Context, cr *ap if cr.CompareVersion("1.17.0") < 0 { pdb.Labels = nil } - err := setControllerReference(owner, pdb, r.Scheme()) + err := setControllerReference(owner, pdb, r.scheme) if err != nil { return errors.Wrap(err, "set owner reference") } diff --git a/pkg/controller/perconaservermongodb/service.go b/pkg/controller/perconaservermongodb/service.go index 8824b9ae9c..26883f5688 100644 --- a/pkg/controller/perconaservermongodb/service.go +++ b/pkg/controller/perconaservermongodb/service.go @@ -31,7 +31,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileReplsetServices(ctx context.Con for _, rs := range repls { // Create headless service service := psmdb.Service(cr, rs) - if err := setControllerReference(cr, service, r.Scheme()); err != nil { + if err := setControllerReference(cr, service, r.scheme); err != nil { return errors.Wrapf(err, "set owner ref for service %s", service.Name) } if err := r.createOrUpdateSvc(ctx, cr, service, true); err != nil { @@ -84,7 +84,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileMongosSvc(ctx context.Context, func (r *ReconcilePerconaServerMongoDB) ensureExternalServices(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.ReplsetSpec, podList *corev1.PodList) error { for _, pod := range podList.Items { service := psmdb.ExternalService(cr, replset, pod.Name) - err := setControllerReference(cr, service, r.Scheme()) + err := setControllerReference(cr, service, r.scheme) if err != nil { return errors.Wrapf(err, "set owner ref for Service %s", service.Name) } @@ -111,7 +111,7 @@ func (r *ReconcilePerconaServerMongoDB) exportService(ctx context.Context, cr *a return nil } se := mcs.ServiceExport(cr.Namespace, svc.Name, ls) - if err := setControllerReference(cr, se, r.Scheme()); err != nil { + if err := setControllerReference(cr, se, r.scheme); err != nil { return errors.Wrapf(err, "set owner ref for serviceexport %s", se.Name) } if err := r.createOrUpdate(ctx, se); err != nil { @@ -261,7 +261,7 @@ func (r *ReconcilePerconaServerMongoDB) removeOutdatedMongosSvc(ctx context.Cont func (r *ReconcilePerconaServerMongoDB) createOrUpdateMongosSvc(ctx context.Context, cr *api.PerconaServerMongoDB, name string) error { svc := psmdb.MongosService(cr, name) - err := setControllerReference(cr, &svc, r.Scheme()) + err := setControllerReference(cr, &svc, r.scheme) if err != nil { return errors.Wrapf(err, "set owner ref for service %s", svc.Name) } diff --git a/pkg/controller/perconaservermongodb/smart.go b/pkg/controller/perconaservermongodb/smart.go index 0040e23a66..8275b5336e 100644 --- a/pkg/controller/perconaservermongodb/smart.go +++ b/pkg/controller/perconaservermongodb/smart.go @@ -151,7 +151,7 @@ func (r *ReconcilePerconaServerMongoDB) smartUpdate(ctx context.Context, cr *api return nil } - hasActiveJobs, err := backup.HasActiveJobs(ctx, r.NewPBMFunc(), r.client, cr, backup.Job{}, backup.NotPITRLock) + hasActiveJobs, err := backup.HasActiveJobs(ctx, r.newPBMFunc, r.client, cr, backup.Job{}, backup.NotPITRLock) if err != nil { if cr.Status.State == api.AppStateError { log.Info("Failed to check active jobs. Proceeding with Smart Update because the cluster is in an error state", "error", err.Error()) @@ -201,7 +201,7 @@ func (r *ReconcilePerconaServerMongoDB) smartUpdate(ctx context.Context, cr *api if sfs.Labels[naming.LabelKubernetesComponent] != "nonVoting" && len(primaryPod.Name) > 0 { forceStepDown := replset.Size == 1 log.Info("doing step down...", "force", forceStepDown) - client, err := r.MongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) + client, err := r.MongoClient().Mongo(ctx, cr, replset, api.RoleClusterAdmin) if err != nil { return fmt.Errorf("failed to get mongo client: %v", err) } @@ -345,7 +345,7 @@ func (r *ReconcilePerconaServerMongoDB) setPrimary(ctx context.Context, cr *api. func (r *ReconcilePerconaServerMongoDB) stepDownPod(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, pod corev1.Pod, seconds int) error { log := logf.FromContext(ctx) - mgoClient, err := r.StandaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) + mgoClient, err := r.MongoClient().Standalone(ctx, cr, rs, api.RoleClusterAdmin, pod) if err != nil { return errors.Wrap(err, "failed to create standalone client") } @@ -364,7 +364,7 @@ func (r *ReconcilePerconaServerMongoDB) stepDownPod(ctx context.Context, cr *api func (r *ReconcilePerconaServerMongoDB) freezePod(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, pod corev1.Pod, seconds int) error { log := logf.FromContext(ctx) - mgoClient, err := r.StandaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) + mgoClient, err := r.MongoClient().Standalone(ctx, cr, rs, api.RoleClusterAdmin, pod) if err != nil { return errors.Wrap(err, "failed to create standalone client") } @@ -383,7 +383,7 @@ func (r *ReconcilePerconaServerMongoDB) freezePod(ctx context.Context, cr *api.P func (r *ReconcilePerconaServerMongoDB) isPodPrimary(ctx context.Context, cr *api.PerconaServerMongoDB, pod corev1.Pod, rs *api.ReplsetSpec) (bool, error) { log := logf.FromContext(ctx) - mgoClient, err := r.StandaloneClientWithRole(ctx, cr, rs, api.RoleClusterAdmin, pod) + mgoClient, err := r.MongoClient().Standalone(ctx, cr, rs, api.RoleClusterAdmin, pod) if err != nil { return false, errors.Wrap(err, "failed to create standalone client") } @@ -434,7 +434,7 @@ func (r *ReconcilePerconaServerMongoDB) smartMongosUpdate(ctx context.Context, c return nil } - hasActiveJobs, err := backup.HasActiveJobs(ctx, r.NewPBMFunc(), r.client, cr, backup.Job{}, backup.NotPITRLock) + hasActiveJobs, err := backup.HasActiveJobs(ctx, r.newPBMFunc, r.client, cr, backup.Job{}, backup.NotPITRLock) if err != nil { return errors.Wrap(err, "failed to check active jobs") } diff --git a/pkg/controller/perconaservermongodb/ssl.go b/pkg/controller/perconaservermongodb/ssl.go index a8c7f29e1f..105193e00a 100644 --- a/pkg/controller/perconaservermongodb/ssl.go +++ b/pkg/controller/perconaservermongodb/ssl.go @@ -103,7 +103,7 @@ func (r *ReconcilePerconaServerMongoDB) reconcileSSL(ctx context.Context, cr *ap } func (r *ReconcilePerconaServerMongoDB) isCertManagerInstalled(ctx context.Context, ns string) (bool, error) { - c := r.newCertManagerCtrlFunc(r.client, r.Scheme(), true) + c := r.newCertManagerCtrlFunc(r.client, r.scheme, true) err := c.Check(ctx, r.restConfig, ns) if err != nil { switch { @@ -150,7 +150,7 @@ func (r *ReconcilePerconaServerMongoDB) doAllStsHasLatestTLS(ctx context.Context func (r *ReconcilePerconaServerMongoDB) createSSLByCertManager(ctx context.Context, cr *api.PerconaServerMongoDB) error { log := logf.FromContext(ctx).WithName("createSSLByCertManager") - dryController := r.newCertManagerCtrlFunc(r.client, r.Scheme(), true) + dryController := r.newCertManagerCtrlFunc(r.client, r.scheme, true) // checking if certificates will be updated applyStatus, err := r.applyCertManagerCertificates(ctx, cr, dryController) if err != nil { @@ -236,7 +236,7 @@ func (r *ReconcilePerconaServerMongoDB) createSSLByCertManager(ctx context.Conte return errors.Wrap(err, "update cert mangager certs") } - c := r.newCertManagerCtrlFunc(r.client, r.Scheme(), false) + c := r.newCertManagerCtrlFunc(r.client, r.scheme, false) if cr.CompareVersion("1.15.0") >= 0 { if err := c.DeleteDeprecatedIssuerIfExists(ctx, cr); err != nil { return errors.Wrap(err, "delete deprecated issuer") @@ -293,7 +293,7 @@ func (r *ReconcilePerconaServerMongoDB) updateCertManagerCerts(ctx context.Conte } } - c := r.newCertManagerCtrlFunc(r.client, r.Scheme(), false) + c := r.newCertManagerCtrlFunc(r.client, r.scheme, false) log.Info("applying new certificates") if _, err := r.applyCertManagerCertificates(ctx, cr, c); err != nil { return errors.Wrap(err, "failed to apply cert-manager certificates") @@ -309,7 +309,7 @@ func (r *ReconcilePerconaServerMongoDB) updateCertManagerCerts(ctx context.Conte // mergeNewCA overwrites current ssl secrets with the old ones, but merges ca.crt from the current secret func (r *ReconcilePerconaServerMongoDB) mergeNewCA(ctx context.Context, cr *api.PerconaServerMongoDB) error { log := logf.FromContext(ctx) - c := tls.NewCertManagerController(r.client, r.Scheme(), false) + c := tls.NewCertManagerController(r.client, r.scheme, false) // In versions 1.14.0 and below, these secrets contained different ca.crt oldCA, err := c.GetMergedCA(ctx, cr, []string{ api.SSLInternalSecretName(cr) + "-old", @@ -451,7 +451,7 @@ func (r *ReconcilePerconaServerMongoDB) createSSLManually(ctx context.Context, c data["tls.crt"] = tlsCert data["tls.key"] = key - owner, err := OwnerRef(cr, r.Scheme()) + owner, err := OwnerRef(cr, r.scheme) if err != nil { return err } diff --git a/pkg/controller/perconaservermongodb/statefulset.go b/pkg/controller/perconaservermongodb/statefulset.go index 52d29f24bf..d71d221e74 100644 --- a/pkg/controller/perconaservermongodb/statefulset.go +++ b/pkg/controller/perconaservermongodb/statefulset.go @@ -91,7 +91,7 @@ func (r *ReconcilePerconaServerMongoDB) getStatefulsetFromReplset(ctx context.Co } sfs := psmdb.NewStatefulSet(sfsName, cr.Namespace) - err := setControllerReference(cr, sfs, r.Scheme()) + err := setControllerReference(cr, sfs, r.scheme) if err != nil { return nil, errors.Wrapf(err, "set owner ref for StatefulSet %s", sfs.Name) } diff --git a/pkg/controller/perconaservermongodb/status_test.go b/pkg/controller/perconaservermongodb/status_test.go index def3032ef5..f52bca5f49 100644 --- a/pkg/controller/perconaservermongodb/status_test.go +++ b/pkg/controller/perconaservermongodb/status_test.go @@ -14,7 +14,6 @@ import ( mcs "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" fakeBackup "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup/fake" faketls "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/tls/fake" "github.com/percona/percona-server-mongodb-operator/version" @@ -39,8 +38,9 @@ func buildFakeClient(objs ...client.Object) *ReconcilePerconaServerMongoDB { cl := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).WithStatusSubresource(objs...).Build() return &ReconcilePerconaServerMongoDB{ - CommonReconciler: common.New(cl, s, fakeBackup.NewPBM, nil), + newPBMFunc: fakeBackup.NewPBM, client: cl, + scheme: s, lockers: newLockStore(), newCertManagerCtrlFunc: faketls.NewCertManagerController, } diff --git a/pkg/controller/perconaservermongodb/suite_test.go b/pkg/controller/perconaservermongodb/suite_test.go index bbe3abcdcd..9471a99a56 100644 --- a/pkg/controller/perconaservermongodb/suite_test.go +++ b/pkg/controller/perconaservermongodb/suite_test.go @@ -19,7 +19,6 @@ import ( "github.com/percona/percona-server-mongodb-operator/clientcmd" "github.com/percona/percona-server-mongodb-operator/pkg/apis" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/tls" "github.com/percona/percona-server-mongodb-operator/version" @@ -80,7 +79,8 @@ func reconciler() *ReconcilePerconaServerMongoDB { return (&ReconcilePerconaServerMongoDB{ client: k8sClient, - CommonReconciler: common.New(k8sClient, k8sClient.Scheme(), backup.NewPBM, nil), + scheme: k8sClient.Scheme(), + newPBMFunc: backup.NewPBM, crons: NewCronRegistry(), lockers: newLockStore(), clientcmd: cli, diff --git a/pkg/controller/perconaservermongodb/users.go b/pkg/controller/perconaservermongodb/users.go index cec509d12c..21eda2b6a6 100644 --- a/pkg/controller/perconaservermongodb/users.go +++ b/pkg/controller/perconaservermongodb/users.go @@ -319,7 +319,7 @@ func (r *ReconcilePerconaServerMongoDB) updateUsers(ctx context.Context, cr *api for i := range repls { replset := repls[i] grp.Go(func() error { - client, err := r.MongoClientWithRole(gCtx, cr, replset, api.RoleUserAdmin) + client, err := r.MongoClient().Mongo(gCtx, cr, replset, api.RoleUserAdmin) if err != nil { return errors.Wrap(err, "dial:") } diff --git a/pkg/controller/perconaservermongodb/version.go b/pkg/controller/perconaservermongodb/version.go index 118a9f22e2..69f8ad36d9 100644 --- a/pkg/controller/perconaservermongodb/version.go +++ b/pkg/controller/perconaservermongodb/version.go @@ -579,7 +579,7 @@ func (r *ReconcilePerconaServerMongoDB) fetchVersionFromMongo(ctx context.Contex return nil } - session, err := r.MongoClientWithRole(ctx, cr, replset, api.RoleClusterAdmin) + session, err := r.MongoClient().Mongo(ctx, cr, replset, api.RoleClusterAdmin) if err != nil { return errors.Wrap(err, "dial") } diff --git a/pkg/controller/perconaservermongodb/version_test.go b/pkg/controller/perconaservermongodb/version_test.go index 644276a440..a40ed9a117 100644 --- a/pkg/controller/perconaservermongodb/version_test.go +++ b/pkg/controller/perconaservermongodb/version_test.go @@ -598,8 +598,9 @@ func TestVersionMeta(t *testing.T) { cl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&tt.cr, &operatorDepl).Build() sv := &version.ServerVersion{Platform: version.PlatformKubernetes} r := &ReconcilePerconaServerMongoDB{ - CommonReconciler: common.New(cl, scheme, nil, nil), + CommonReconciler: common.New(nil), client: cl, + scheme: scheme, serverVersion: sv, } diff --git a/pkg/controller/perconaservermongodbbackup/backup.go b/pkg/controller/perconaservermongodbbackup/backup.go index 74fcd0f47f..7893806445 100644 --- a/pkg/controller/perconaservermongodbbackup/backup.go +++ b/pkg/controller/perconaservermongodbbackup/backup.go @@ -43,7 +43,7 @@ func (r *ReconcilePerconaServerMongoDBBackup) newBackup(ctx context.Context, clu if cluster == nil { return new(Backup), nil } - cn, err := r.NewPBM(ctx, cluster) + cn, err := r.newPBMFunc(ctx, r.client, cluster) if err != nil { return nil, errors.Wrap(err, "create pbm object") } diff --git a/pkg/controller/perconaservermongodbbackup/perconaservermongodbbackup_controller.go b/pkg/controller/perconaservermongodbbackup/perconaservermongodbbackup_controller.go index 4d0dcbd6be..5e3b4af68c 100644 --- a/pkg/controller/perconaservermongodbbackup/perconaservermongodbbackup_controller.go +++ b/pkg/controller/perconaservermongodbbackup/perconaservermongodbbackup_controller.go @@ -11,6 +11,7 @@ import ( corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -29,7 +30,6 @@ import ( "github.com/percona/percona-server-mongodb-operator/clientcmd" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/k8s" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" @@ -60,9 +60,10 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) { } return &ReconcilePerconaServerMongoDBBackup{ - CommonReconciler: common.New(mgr.GetClient(), mgr.GetScheme(), backup.NewPBM, nil), - client: mgr.GetClient(), - clientcmd: cli, + client: mgr.GetClient(), + scheme: mgr.GetScheme(), + clientcmd: cli, + newPBMFunc: backup.NewPBM, }, nil } @@ -87,11 +88,13 @@ var _ reconcile.Reconciler = &ReconcilePerconaServerMongoDBBackup{} // ReconcilePerconaServerMongoDBBackup reconciles a PerconaServerMongoDBBackup object type ReconcilePerconaServerMongoDBBackup struct { - common.CommonReconciler // This client, initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver client client.Client + scheme *runtime.Scheme clientcmd *clientcmd.Client + + newPBMFunc backup.NewPBMFunc } // Reconcile reads that state of the cluster for a PerconaServerMongoDBBackup object and makes changes based on the state read @@ -230,7 +233,7 @@ func (r *ReconcilePerconaServerMongoDBBackup) reconcile( return status, errors.Wrap(err, "failed to run backup") } - cjobs, err := backup.HasActiveJobs(ctx, r.NewPBMFunc(), r.client, cluster, backup.NewBackupJob(cr.Name), backup.NotPITRLock) + cjobs, err := backup.HasActiveJobs(ctx, r.newPBMFunc, r.client, cluster, backup.NewBackupJob(cr.Name), backup.NotPITRLock) if err != nil { return status, errors.Wrap(err, "check for concurrent jobs") } diff --git a/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go b/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go index afb86cc662..52b1553ce8 100644 --- a/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go +++ b/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go @@ -10,6 +10,7 @@ import ( corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/util/retry" @@ -25,7 +26,6 @@ import ( "github.com/percona/percona-server-mongodb-operator/clientcmd" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" @@ -52,9 +52,10 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) { } return &ReconcilePerconaServerMongoDBRestore{ - CommonReconciler: common.New(mgr.GetClient(), mgr.GetScheme(), backup.NewPBM, nil), - client: mgr.GetClient(), - clientcmd: cli, + client: mgr.GetClient(), + scheme: mgr.GetScheme(), + clientcmd: cli, + newPBMFunc: backup.NewPBM, }, nil } @@ -80,10 +81,13 @@ var _ reconcile.Reconciler = &ReconcilePerconaServerMongoDBRestore{} type ReconcilePerconaServerMongoDBRestore struct { // This client, initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver - common.CommonReconciler + psmdb.MongoProviderBase client client.Client // TODO: use CommonReconciler client + scheme *runtime.Scheme clientcmd *clientcmd.Client + + newPBMFunc backup.NewPBMFunc } // Reconcile reads that state of the cluster for a PerconaServerMongoDBRestore object and makes changes based on the state read diff --git a/pkg/controller/perconaservermongodbrestore/physical.go b/pkg/controller/perconaservermongodbrestore/physical.go index 62565848f0..2a42136b27 100644 --- a/pkg/controller/perconaservermongodbrestore/physical.go +++ b/pkg/controller/perconaservermongodbrestore/physical.go @@ -358,7 +358,7 @@ func (r *ReconcilePerconaServerMongoDBRestore) finishPhysicalRestore(ctx context return nil } rs := cluster.Spec.Replset(s.Labels[naming.LabelKubernetesReplset]) - c, err := r.MongoClientWithRole(ctx, cluster, rs, api.RoleClusterAdmin) + c, err := r.MongoClient().Mongo(ctx, cluster, rs, api.RoleClusterAdmin) if err != nil { wait = true @@ -368,7 +368,7 @@ func (r *ReconcilePerconaServerMongoDBRestore) finishPhysicalRestore(ctx context return err } updateConfig := func(pod corev1.Pod) error { - cli, err := r.StandaloneClientWithRole(ctx, cluster, rs, api.RoleClusterAdmin, pod) + cli, err := r.MongoClient().Standalone(ctx, cluster, rs, api.RoleClusterAdmin, pod) if err != nil { return nil } diff --git a/pkg/controller/perconaservermongodbrestore/validate.go b/pkg/controller/perconaservermongodbrestore/validate.go index dd9bbf29c4..5c888d3a5a 100644 --- a/pkg/controller/perconaservermongodbrestore/validate.go +++ b/pkg/controller/perconaservermongodbrestore/validate.go @@ -32,7 +32,7 @@ func (r *ReconcilePerconaServerMongoDBRestore) validate(ctx context.Context, cr return errors.Wrap(err, "get storage") } - pbmc, err := r.NewPBM(ctx, cluster) + pbmc, err := r.newPBMFunc(ctx, r.client, cluster) if err != nil { return errWaitingPBM } diff --git a/pkg/controller/perconaservermongodbrestore/validate_test.go b/pkg/controller/perconaservermongodbrestore/validate_test.go index b4f826d044..68905e1a7a 100644 --- a/pkg/controller/perconaservermongodbrestore/validate_test.go +++ b/pkg/controller/perconaservermongodbrestore/validate_test.go @@ -11,7 +11,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" fakeBackup "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup/fake" ) @@ -167,7 +166,8 @@ func fakeReconciler(objs ...client.Object) *ReconcilePerconaServerMongoDBRestore cl := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).WithStatusSubresource(objs...).Build() return &ReconcilePerconaServerMongoDBRestore{ - CommonReconciler: common.New(cl, s, fakeBackup.NewPBM, nil), - client: cl, + client: cl, + scheme: s, + newPBMFunc: fakeBackup.NewPBM, } } diff --git a/pkg/psmdb/provider.go b/pkg/psmdb/provider.go index fba07e67c2..049bc28c09 100644 --- a/pkg/psmdb/provider.go +++ b/pkg/psmdb/provider.go @@ -15,17 +15,13 @@ import ( type MongoClientProvider interface { Mongo(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) Mongos(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole) (mongo.Client, error) - Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole, host string, tlsEnabled bool) (mongo.Client, error) + Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole, pod corev1.Pod) (mongo.Client, error) } type mongoClientProvider struct { k8sclient client.Client } -func NewProvider(c client.Client) *mongoClientProvider { - return &mongoClientProvider{k8sclient: c} -} - func (p *mongoClientProvider) Mongo(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole) (mongo.Client, error) { c, err := GetCredentials(ctx, p.k8sclient, cr, role) if err != nil { @@ -44,13 +40,37 @@ func (p *mongoClientProvider) Mongos(ctx context.Context, cr *api.PerconaServerM return mongosClient(ctx, p.k8sclient, cr, c) } -func (p *mongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.SystemUserRole, host string, tlsEnabled bool) (mongo.Client, error) { +func (p *mongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec, role api.SystemUserRole, pod corev1.Pod) (mongo.Client, error) { c, err := GetCredentials(ctx, p.k8sclient, cr, role) if err != nil { return nil, errors.Wrap(err, "failed to get credentials") } + host, err := MongoHost(ctx, p.k8sclient, cr, cr.Spec.ClusterServiceDNSMode, rs, rs.Expose.Enabled, pod) + if err != nil { + return nil, errors.Wrap(err, "failed to get mongo host") + } + + return standaloneClient(ctx, p.k8sclient, cr, c, host, cr.TLSEnabled()) +} + +type MongoProviderBase struct { + cl client.Client - return standaloneClient(ctx, p.k8sclient, cr, c, host, tlsEnabled) + provider MongoClientProvider +} + +func NewProviderBase(cl client.Client, provider MongoClientProvider) MongoProviderBase { + return MongoProviderBase{ + cl: cl, + provider: provider, + } +} + +func (provider *MongoProviderBase) MongoClient() MongoClientProvider { + if provider.provider == nil { + return &mongoClientProvider{k8sclient: provider.cl} + } + return provider.provider } func getUserSecret(ctx context.Context, cl client.Reader, cr *api.PerconaServerMongoDB, name string) (corev1.Secret, error) { From 879163f948c96919c77044b2c78cc95059265a5b Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Tue, 20 May 2025 17:09:42 +0300 Subject: [PATCH 05/10] fix --- pkg/controller/perconaservermongodb/psmdb_controller.go | 2 -- pkg/controller/perconaservermongodb/version_test.go | 8 +++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/pkg/controller/perconaservermongodb/psmdb_controller.go b/pkg/controller/perconaservermongodb/psmdb_controller.go index f2c262fa79..4ed918cb97 100644 --- a/pkg/controller/perconaservermongodb/psmdb_controller.go +++ b/pkg/controller/perconaservermongodb/psmdb_controller.go @@ -35,7 +35,6 @@ import ( "github.com/percona/percona-server-mongodb-operator/clientcmd" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup" @@ -172,7 +171,6 @@ func NewCronRegistry() CronRegistry { // ReconcilePerconaServerMongoDB reconciles a PerconaServerMongoDB object type ReconcilePerconaServerMongoDB struct { - common.CommonReconciler psmdb.MongoProviderBase // This client, initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver diff --git a/pkg/controller/perconaservermongodb/version_test.go b/pkg/controller/perconaservermongodb/version_test.go index a40ed9a117..16effab84b 100644 --- a/pkg/controller/perconaservermongodb/version_test.go +++ b/pkg/controller/perconaservermongodb/version_test.go @@ -24,7 +24,6 @@ import ( "github.com/percona/percona-server-mongodb-operator/pkg/apis" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" - "github.com/percona/percona-server-mongodb-operator/pkg/controller/common" "github.com/percona/percona-server-mongodb-operator/pkg/k8s" "github.com/percona/percona-server-mongodb-operator/version" ) @@ -598,10 +597,9 @@ func TestVersionMeta(t *testing.T) { cl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&tt.cr, &operatorDepl).Build() sv := &version.ServerVersion{Platform: version.PlatformKubernetes} r := &ReconcilePerconaServerMongoDB{ - CommonReconciler: common.New(nil), - client: cl, - scheme: scheme, - serverVersion: sv, + client: cl, + scheme: scheme, + serverVersion: sv, } if err := r.setCRVersion(context.TODO(), &tt.cr); err != nil { From f87bcc82e849eb94ddcb6bda9d621ffa29a6c064 Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Tue, 20 May 2025 17:18:04 +0300 Subject: [PATCH 06/10] fix unit-test --- pkg/controller/perconaservermongodb/status_test.go | 2 ++ .../perconaservermongodbrestore_controller.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/controller/perconaservermongodb/status_test.go b/pkg/controller/perconaservermongodb/status_test.go index f52bca5f49..98a58b4ee3 100644 --- a/pkg/controller/perconaservermongodb/status_test.go +++ b/pkg/controller/perconaservermongodb/status_test.go @@ -14,6 +14,7 @@ import ( mcs "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/psmdb" fakeBackup "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/backup/fake" faketls "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/tls/fake" "github.com/percona/percona-server-mongodb-operator/version" @@ -38,6 +39,7 @@ func buildFakeClient(objs ...client.Object) *ReconcilePerconaServerMongoDB { cl := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).WithStatusSubresource(objs...).Build() return &ReconcilePerconaServerMongoDB{ + MongoProviderBase: psmdb.NewProviderBase(cl, nil), newPBMFunc: fakeBackup.NewPBM, client: cl, scheme: s, diff --git a/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go b/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go index 52b1553ce8..4be5a3dece 100644 --- a/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go +++ b/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go @@ -83,7 +83,7 @@ type ReconcilePerconaServerMongoDBRestore struct { // that reads objects from the cache and writes to the apiserver psmdb.MongoProviderBase - client client.Client // TODO: use CommonReconciler client + client client.Client scheme *runtime.Scheme clientcmd *clientcmd.Client From a5667375f54e11ebac6e10b277c729406dade92c Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Wed, 21 May 2025 13:35:29 +0300 Subject: [PATCH 07/10] fix --- pkg/controller/perconaservermongodb/psmdb_controller.go | 1 + .../perconaservermongodbrestore_controller.go | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/controller/perconaservermongodb/psmdb_controller.go b/pkg/controller/perconaservermongodb/psmdb_controller.go index 4ed918cb97..91aba24e7f 100644 --- a/pkg/controller/perconaservermongodb/psmdb_controller.go +++ b/pkg/controller/perconaservermongodb/psmdb_controller.go @@ -87,6 +87,7 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) { } return &ReconcilePerconaServerMongoDB{ + MongoProviderBase: psmdb.NewProviderBase(client, nil), client: client, scheme: client.Scheme(), newPBMFunc: backup.NewPBM, diff --git a/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go b/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go index 4be5a3dece..040f9289ed 100644 --- a/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go +++ b/pkg/controller/perconaservermongodbrestore/perconaservermongodbrestore_controller.go @@ -52,10 +52,11 @@ func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) { } return &ReconcilePerconaServerMongoDBRestore{ - client: mgr.GetClient(), - scheme: mgr.GetScheme(), - clientcmd: cli, - newPBMFunc: backup.NewPBM, + MongoProviderBase: psmdb.NewProviderBase(mgr.GetClient(), nil), + client: mgr.GetClient(), + scheme: mgr.GetScheme(), + clientcmd: cli, + newPBMFunc: backup.NewPBM, }, nil } From 35a2e22e4f8289f1835afd9ab8bf75c1212359c1 Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Wed, 21 May 2025 14:03:02 +0300 Subject: [PATCH 08/10] fix manifests --- deploy/bundle.yaml | 2 +- deploy/cw-bundle.yaml | 2 +- deploy/cw-operator.yaml | 2 +- deploy/operator.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index dda12eec14..9d863e068a 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -19788,7 +19788,7 @@ spec: serviceAccountName: percona-server-mongodb-operator containers: - name: percona-server-mongodb-operator - image: percona/percona-server-mongodb-operator:1.20.0 + image: perconalab/percona-server-mongodb-operator:main imagePullPolicy: Always livenessProbe: failureThreshold: 3 diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index 111834cb61..010ee9f9f9 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -19809,7 +19809,7 @@ spec: serviceAccountName: percona-server-mongodb-operator containers: - name: percona-server-mongodb-operator - image: percona/percona-server-mongodb-operator:1.20.0 + image: perconalab/percona-server-mongodb-operator:main imagePullPolicy: Always livenessProbe: failureThreshold: 3 diff --git a/deploy/cw-operator.yaml b/deploy/cw-operator.yaml index e1effb043b..b8ec3d38e6 100644 --- a/deploy/cw-operator.yaml +++ b/deploy/cw-operator.yaml @@ -15,7 +15,7 @@ spec: serviceAccountName: percona-server-mongodb-operator containers: - name: percona-server-mongodb-operator - image: percona/percona-server-mongodb-operator:1.20.0 + image: perconalab/percona-server-mongodb-operator:main imagePullPolicy: Always livenessProbe: failureThreshold: 3 diff --git a/deploy/operator.yaml b/deploy/operator.yaml index db09479e99..90d4d04a51 100644 --- a/deploy/operator.yaml +++ b/deploy/operator.yaml @@ -15,7 +15,7 @@ spec: serviceAccountName: percona-server-mongodb-operator containers: - name: percona-server-mongodb-operator - image: percona/percona-server-mongodb-operator:1.20.0 + image: perconalab/percona-server-mongodb-operator:main imagePullPolicy: Always livenessProbe: failureThreshold: 3 From 81186a8ee53968ff457a070540c53f14818f1f85 Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Wed, 21 May 2025 22:34:23 +0300 Subject: [PATCH 09/10] fix tests --- .../perconaservermongodbrestore/physical.go | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/pkg/controller/perconaservermongodbrestore/physical.go b/pkg/controller/perconaservermongodbrestore/physical.go index e42555673a..b0738c8f19 100644 --- a/pkg/controller/perconaservermongodbrestore/physical.go +++ b/pkg/controller/perconaservermongodbrestore/physical.go @@ -92,9 +92,13 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( } status.State = psmdbv1.RestoreStateWaiting + return status, nil } - if cr.Status.State == psmdbv1.RestoreStateWaiting || status.State == psmdbv1.RestoreStateWaiting { + stdoutBuf := &bytes.Buffer{} + stderrBuf := &bytes.Buffer{} + + if cr.Status.State == psmdbv1.RestoreStateWaiting { if err := r.prepareStatefulSetsForPhysicalRestore(ctx, cluster); err != nil { return status, errors.Wrap(err, "prepare statefulsets for physical restore") } @@ -104,12 +108,12 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( return status, errors.Wrap(err, "check if statefulsets are ready for physical restore") } - if (!sfsReady && cr.Status.State != psmdbv1.RestoreStateRunning) || cr.Status.State == psmdbv1.RestoreStateNew { + if !sfsReady { log.Info("Waiting for statefulsets to be ready before restore", "ready", sfsReady) return status, nil } - if sfsReady && cr.Spec.PITR != nil { + if cr.Spec.PITR != nil { rsReady, err := r.checkIfReplsetsAreReadyForPhysicalRestore(ctx, cluster) if err != nil { return status, errors.Wrap(err, "check if replsets are ready for physical restore") @@ -124,12 +128,7 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( return status, nil } } - } - stdoutBuf := &bytes.Buffer{} - stderrBuf := &bytes.Buffer{} - - if cr.Status.State == psmdbv1.RestoreStateWaiting { rs := replsets[0] pbmAgentsReady, err := r.checkIfPBMAgentsReadyForPhysicalRestore(ctx, cluster) @@ -198,8 +197,11 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( } return status, errors.Wrap(err, "get pod") } + if !pod.DeletionTimestamp.IsZero() { + return status, nil + } - if pod.Spec.Containers[0].Name == naming.ContainerBackupAgent && pod.DeletionTimestamp == nil { + if !hasContainerName(pod.Spec.Containers, naming.ContainerBackupAgent) { meta := backup.BackupMeta{} notFound := false @@ -266,7 +268,6 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( return status, nil } - // status.State = psmdbv1.RestoreStateReady restoreIsDone = true } @@ -296,20 +297,17 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( status.State = psmdbv1.RestoreStateReady err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - c := &psmdbv1.PerconaServerMongoDB{} - err := r.client.Get(ctx, types.NamespacedName{Name: cluster.Name, Namespace: cluster.Namespace}, c) - if err != nil { + c := new(psmdbv1.PerconaServerMongoDB) + if err := r.client.Get(ctx, client.ObjectKeyFromObject(cluster), c); err != nil { return err } - orig := c.DeepCopy() - if c.Annotations == nil { c.Annotations = make(map[string]string) } c.Annotations[psmdbv1.AnnotationResyncPBM] = "true" - return r.client.Patch(ctx, c, client.MergeFrom(orig)) + return r.client.Update(ctx, c) }) if err != nil { return status, errors.Wrapf(err, "annotate psmdb/%s for PBM resync", cluster.Name) @@ -318,12 +316,27 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( return status, nil } +func hasContainerName(containers []corev1.Container, name string) bool { + for _, c := range containers { + if c.Name == name { + return true + } + } + return false +} + func (r *ReconcilePerconaServerMongoDBRestore) finishPhysicalRestore(ctx context.Context, cluster *api.PerconaServerMongoDB) (bool, error) { stsIsUpdated := true if err := r.updateMongodSts(ctx, cluster, func(sts *appsv1.StatefulSet) error { - if sts.Spec.Template.Spec.Containers[0].Name == naming.ContainerBackupAgent { - stsIsUpdated = false - } else if sts.Annotations[psmdbv1.AnnotationRestoreInProgress] != "true" { + if !sts.DeletionTimestamp.IsZero() { + return nil + } + + if !hasContainerName(sts.Spec.Template.Spec.Containers, naming.ContainerBackupAgent) { + return errors.Errorf("statefulsets weren't deleted") + } + + if sts.Annotations[psmdbv1.AnnotationRestoreInProgress] != "true" { stsIsUpdated = false sts.Annotations[psmdbv1.AnnotationRestoreInProgress] = "true" } From dc8663f5aaf6a74fbb020b7fe5caadc23de2cc9c Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Thu, 22 May 2025 09:47:42 +0300 Subject: [PATCH 10/10] small fix --- .../perconaservermongodbrestore/physical.go | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/pkg/controller/perconaservermongodbrestore/physical.go b/pkg/controller/perconaservermongodbrestore/physical.go index b0738c8f19..b8a8577db4 100644 --- a/pkg/controller/perconaservermongodbrestore/physical.go +++ b/pkg/controller/perconaservermongodbrestore/physical.go @@ -288,7 +288,9 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( finished, err := r.finishPhysicalRestore(ctx, cluster) if err != nil { - return status, err // TODO: shouldn't return error + log.Error(err, "Failed to recover the cluster after the restore") + status.State = psmdbv1.RestoreStateReady + return status, nil } if !finished { return status, nil @@ -296,23 +298,6 @@ func (r *ReconcilePerconaServerMongoDBRestore) reconcilePhysicalRestore( status.State = psmdbv1.RestoreStateReady - err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - c := new(psmdbv1.PerconaServerMongoDB) - if err := r.client.Get(ctx, client.ObjectKeyFromObject(cluster), c); err != nil { - return err - } - - if c.Annotations == nil { - c.Annotations = make(map[string]string) - } - c.Annotations[psmdbv1.AnnotationResyncPBM] = "true" - - return r.client.Update(ctx, c) - }) - if err != nil { - return status, errors.Wrapf(err, "annotate psmdb/%s for PBM resync", cluster.Name) - } - return status, nil } @@ -415,6 +400,22 @@ func (r *ReconcilePerconaServerMongoDBRestore) finishPhysicalRestore(ctx context return false, nil } + if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + c := new(psmdbv1.PerconaServerMongoDB) + if err := r.client.Get(ctx, client.ObjectKeyFromObject(cluster), c); err != nil { + return err + } + + if c.Annotations == nil { + c.Annotations = make(map[string]string) + } + c.Annotations[psmdbv1.AnnotationResyncPBM] = "true" + + return r.client.Update(ctx, c) + }); err != nil { + return false, errors.Wrapf(err, "annotate psmdb/%s for PBM resync", cluster.Name) + } + if err := r.updateMongodSts(ctx, cluster, func(sts *appsv1.StatefulSet) error { if sts.Annotations[psmdbv1.AnnotationRestoreInProgress] == "true" { delete(sts.Annotations, psmdbv1.AnnotationRestoreInProgress)