github.com/percona/percona-xtradb-cluster-operator@v1.14.0/pkg/controller/pxc/users_without_dp.go (about)

     1  package pxc
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  
     7  	"github.com/hashicorp/go-version"
     8  	"github.com/pkg/errors"
     9  	corev1 "k8s.io/api/core/v1"
    10  	"sigs.k8s.io/controller-runtime/pkg/client"
    11  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    12  
    13  	api "github.com/percona/percona-xtradb-cluster-operator/pkg/apis/pxc/v1"
    14  	"github.com/percona/percona-xtradb-cluster-operator/pkg/pxc/app/statefulset"
    15  	"github.com/percona/percona-xtradb-cluster-operator/pkg/pxc/users"
    16  )
    17  
    18  func (r *ReconcilePerconaXtraDBCluster) updateUsersWithoutDP(ctx context.Context, cr *api.PerconaXtraDBCluster, secrets, internalSecrets *corev1.Secret) (*userUpdateActions, error) {
    19  	res := &userUpdateActions{}
    20  
    21  	for _, u := range users.UserNames {
    22  		if _, ok := secrets.Data[u]; !ok {
    23  			continue
    24  		}
    25  
    26  		switch u {
    27  		case users.Root:
    28  			if err := r.handleRootUserWithoutDP(ctx, cr, secrets, internalSecrets, res); err != nil {
    29  				return res, err
    30  			}
    31  		case users.Operator:
    32  			if err := r.handleOperatorUserWithoutDP(ctx, cr, secrets, internalSecrets, res); err != nil {
    33  				return res, err
    34  			}
    35  		case users.Monitor:
    36  			if err := r.handleMonitorUserWithoutDP(ctx, cr, secrets, internalSecrets, res); err != nil {
    37  				return res, err
    38  			}
    39  		case users.Xtrabackup:
    40  			if err := r.handleXtrabackupUserWithoutDP(ctx, cr, secrets, internalSecrets, res); err != nil {
    41  				return res, err
    42  			}
    43  		case users.Replication:
    44  			if err := r.handleReplicationUserWithoutDP(ctx, cr, secrets, internalSecrets, res); err != nil {
    45  				return res, err
    46  			}
    47  		case users.ProxyAdmin:
    48  			if err := r.handleProxyadminUserWithoutDP(ctx, cr, secrets, internalSecrets, res); err != nil {
    49  				return res, err
    50  			}
    51  		case users.PMMServer, users.PMMServerKey:
    52  			if err := r.handlePMMUser(ctx, cr, secrets, internalSecrets, res); err != nil {
    53  				return res, err
    54  			}
    55  		}
    56  	}
    57  
    58  	return res, nil
    59  }
    60  func (r *ReconcilePerconaXtraDBCluster) handleRootUserWithoutDP(ctx context.Context, cr *api.PerconaXtraDBCluster, secrets, internalSecrets *corev1.Secret, actions *userUpdateActions) error {
    61  	if cr.Status.Status != api.AppStateReady && !r.invalidPasswordApplied(cr.Status) {
    62  		return nil
    63  	}
    64  
    65  	log := logf.FromContext(ctx)
    66  
    67  	user := &users.SysUser{
    68  		Name:  users.Root,
    69  		Pass:  string(secrets.Data[users.Root]),
    70  		Hosts: []string{"localhost", "%"},
    71  	}
    72  
    73  	if err := r.updateUserPassExpirationPolicy(ctx, cr, internalSecrets, user); err != nil {
    74  		return err
    75  	}
    76  
    77  	if bytes.Equal(secrets.Data[user.Name], internalSecrets.Data[user.Name]) {
    78  		return nil
    79  	}
    80  
    81  	log.Info("Password changed, updating user", "user", user.Name)
    82  
    83  	err := r.updateUserPassWithoutDP(cr, secrets, internalSecrets, user)
    84  	if err != nil {
    85  		return errors.Wrap(err, "update root users pass")
    86  	}
    87  	log.Info("User password updated", "user", user.Name)
    88  
    89  	if err := r.updateMySQLInitFile(ctx, cr, internalSecrets, user); err != nil {
    90  		return errors.Wrap(err, "update mysql init file")
    91  	}
    92  
    93  	err = r.syncPXCUsersWithProxySQL(ctx, cr)
    94  	if err != nil {
    95  		return errors.Wrap(err, "sync users")
    96  	}
    97  
    98  	orig := internalSecrets.DeepCopy()
    99  	internalSecrets.Data[user.Name] = secrets.Data[user.Name]
   100  	err = r.client.Patch(context.TODO(), internalSecrets, client.MergeFrom(orig))
   101  	if err != nil {
   102  		return errors.Wrap(err, "update internal secrets root user password")
   103  	}
   104  	log.Info("Internal secrets updated", "user", user.Name)
   105  
   106  	return nil
   107  }
   108  
   109  func (r *ReconcilePerconaXtraDBCluster) handleOperatorUserWithoutDP(ctx context.Context, cr *api.PerconaXtraDBCluster, secrets, internalSecrets *corev1.Secret, actions *userUpdateActions) error {
   110  	log := logf.FromContext(ctx)
   111  
   112  	user := &users.SysUser{
   113  		Name:  users.Operator,
   114  		Pass:  string(secrets.Data[users.Operator]),
   115  		Hosts: []string{"%"},
   116  	}
   117  
   118  	if cr.Status.PXC.Ready > 0 {
   119  		err := r.manageOperatorAdminUser(ctx, cr, secrets, internalSecrets)
   120  		if err != nil {
   121  			return errors.Wrap(err, "manage operator admin user")
   122  		}
   123  
   124  		if err := r.updateUserPassExpirationPolicy(ctx, cr, internalSecrets, user); err != nil {
   125  			return err
   126  		}
   127  	}
   128  
   129  	if cr.Status.Status != api.AppStateReady && !r.invalidPasswordApplied(cr.Status) {
   130  		return nil
   131  	}
   132  
   133  	if bytes.Equal(secrets.Data[user.Name], internalSecrets.Data[user.Name]) {
   134  		return nil
   135  	}
   136  
   137  	log.Info("Password changed, updating user", "user", user.Name)
   138  
   139  	err := r.updateUserPassWithoutDP(cr, secrets, internalSecrets, user)
   140  	if err != nil {
   141  		return errors.Wrap(err, "update operator users pass")
   142  	}
   143  	log.Info("User password updated", "user", user.Name)
   144  
   145  	if err := r.updateMySQLInitFile(ctx, cr, internalSecrets, user); err != nil {
   146  		return errors.Wrap(err, "update mysql init file")
   147  	}
   148  
   149  	orig := internalSecrets.DeepCopy()
   150  	internalSecrets.Data[user.Name] = secrets.Data[user.Name]
   151  	err = r.client.Patch(context.TODO(), internalSecrets, client.MergeFrom(orig))
   152  	if err != nil {
   153  		return errors.Wrap(err, "update internal users secrets operator user password")
   154  	}
   155  	log.Info("Internal secrets updated", "user", user.Name)
   156  
   157  	actions.restartProxy = true
   158  	return nil
   159  }
   160  
   161  func (r *ReconcilePerconaXtraDBCluster) handleMonitorUserWithoutDP(ctx context.Context, cr *api.PerconaXtraDBCluster, secrets, internalSecrets *corev1.Secret, actions *userUpdateActions) error {
   162  	log := logf.FromContext(ctx)
   163  
   164  	user := &users.SysUser{
   165  		Name:  users.Monitor,
   166  		Pass:  string(secrets.Data[users.Monitor]),
   167  		Hosts: []string{"%"},
   168  	}
   169  
   170  	if cr.Status.PXC.Ready > 0 {
   171  		if err := r.updateUserPassExpirationPolicy(ctx, cr, internalSecrets, user); err != nil {
   172  			return err
   173  		}
   174  
   175  		um, err := getUserManager(cr, internalSecrets)
   176  		if err != nil {
   177  			return err
   178  		}
   179  		defer um.Close()
   180  
   181  		if cr.CompareVersionWith("1.6.0") >= 0 {
   182  			err := r.updateMonitorUserGrant(ctx, cr, internalSecrets, um)
   183  			if err != nil {
   184  				return errors.Wrap(err, "update monitor user grant")
   185  			}
   186  		}
   187  
   188  		if cr.CompareVersionWith("1.10.0") >= 0 {
   189  			mysqlVersion := cr.Status.PXC.Version
   190  			if mysqlVersion == "" {
   191  				var err error
   192  				mysqlVersion, err = r.mysqlVersion(ctx, cr, statefulset.NewNode(cr))
   193  				if err != nil {
   194  					if errors.Is(err, versionNotReadyErr) {
   195  						return nil
   196  					}
   197  					return errors.Wrap(err, "retrieving pxc version")
   198  				}
   199  			}
   200  
   201  			if mysqlVersion != "" {
   202  				ver, err := version.NewVersion(mysqlVersion)
   203  				if err != nil {
   204  					return errors.Wrap(err, "invalid pxc version")
   205  				}
   206  
   207  				if !ver.LessThan(privSystemUserAddedIn) {
   208  					if err := r.grantMonitorUserPrivilege(ctx, cr, internalSecrets, um); err != nil {
   209  						return errors.Wrap(err, "monitor user grant system privilege")
   210  					}
   211  				}
   212  			}
   213  		}
   214  	}
   215  
   216  	if cr.Status.Status != api.AppStateReady && !r.invalidPasswordApplied(cr.Status) {
   217  		return nil
   218  	}
   219  
   220  	if bytes.Equal(secrets.Data[user.Name], internalSecrets.Data[user.Name]) {
   221  		return nil
   222  	}
   223  
   224  	log.Info("Password changed, updating user", "user", user.Name)
   225  
   226  	err := r.updateUserPassWithoutDP(cr, secrets, internalSecrets, user)
   227  	if err != nil {
   228  		return errors.Wrap(err, "update monitor users pass")
   229  	}
   230  	log.Info("User password updated", "user", user.Name)
   231  
   232  	if err := r.updateMySQLInitFile(ctx, cr, internalSecrets, user); err != nil {
   233  		return errors.Wrap(err, "update mysql init file")
   234  	}
   235  
   236  	if cr.Spec.ProxySQLEnabled() {
   237  		err := r.updateProxyUser(cr, internalSecrets, user)
   238  		if err != nil {
   239  			return errors.Wrap(err, "update monitor users pass")
   240  		}
   241  		log.Info("Proxy user updated", "user", user.Name)
   242  	}
   243  
   244  	actions.restartProxy = true
   245  	if cr.Spec.PMM != nil && cr.Spec.PMM.IsEnabled(internalSecrets) {
   246  		actions.restartPXC = true
   247  	}
   248  
   249  	orig := internalSecrets.DeepCopy()
   250  	internalSecrets.Data[user.Name] = secrets.Data[user.Name]
   251  	err = r.client.Patch(context.TODO(), internalSecrets, client.MergeFrom(orig))
   252  	if err != nil {
   253  		return errors.Wrap(err, "update internal users secrets monitor user password")
   254  	}
   255  	log.Info("Internal secrets updated", "user", user.Name)
   256  
   257  	return nil
   258  }
   259  
   260  func (r *ReconcilePerconaXtraDBCluster) handleXtrabackupUserWithoutDP(ctx context.Context, cr *api.PerconaXtraDBCluster, secrets, internalSecrets *corev1.Secret, actions *userUpdateActions) error {
   261  	log := logf.FromContext(ctx)
   262  
   263  	user := &users.SysUser{
   264  		Name:  users.Xtrabackup,
   265  		Pass:  string(secrets.Data[users.Xtrabackup]),
   266  		Hosts: []string{"localhost"},
   267  	}
   268  
   269  	if cr.CompareVersionWith("1.7.0") >= 0 {
   270  		user.Hosts = []string{"%"}
   271  	}
   272  
   273  	if cr.Status.PXC.Ready > 0 {
   274  		if err := r.updateUserPassExpirationPolicy(ctx, cr, internalSecrets, user); err != nil {
   275  			return err
   276  		}
   277  
   278  		if cr.CompareVersionWith("1.7.0") >= 0 {
   279  			// monitor user need more grants for work in version more then 1.6.0
   280  			err := r.updateXtrabackupUserGrant(ctx, cr, internalSecrets)
   281  			if err != nil {
   282  				return errors.Wrap(err, "update xtrabackup user grant")
   283  			}
   284  		}
   285  	}
   286  
   287  	if cr.Status.Status != api.AppStateReady && !r.invalidPasswordApplied(cr.Status) {
   288  		return nil
   289  	}
   290  
   291  	if bytes.Equal(secrets.Data[user.Name], internalSecrets.Data[user.Name]) {
   292  		return nil
   293  	}
   294  
   295  	log.Info("Password changed, updating user", "user", user.Name)
   296  
   297  	err := r.updateUserPassWithoutDP(cr, secrets, internalSecrets, user)
   298  	if err != nil {
   299  		return errors.Wrap(err, "update xtrabackup users pass")
   300  	}
   301  	log.Info("User password updated", "user", user.Name)
   302  
   303  	if err := r.updateMySQLInitFile(ctx, cr, internalSecrets, user); err != nil {
   304  		return errors.Wrap(err, "update mysql init file")
   305  	}
   306  
   307  	orig := internalSecrets.DeepCopy()
   308  	internalSecrets.Data[user.Name] = secrets.Data[user.Name]
   309  	err = r.client.Patch(context.TODO(), internalSecrets, client.MergeFrom(orig))
   310  	if err != nil {
   311  		return errors.Wrap(err, "update internal users secrets xtrabackup user password")
   312  	}
   313  	log.Info("Internal secrets updated", "user", user.Name)
   314  
   315  	actions.restartPXC = true
   316  	return nil
   317  }
   318  
   319  func (r *ReconcilePerconaXtraDBCluster) handleReplicationUserWithoutDP(ctx context.Context, cr *api.PerconaXtraDBCluster, secrets, internalSecrets *corev1.Secret, actions *userUpdateActions) error {
   320  	log := logf.FromContext(ctx)
   321  
   322  	if cr.CompareVersionWith("1.9.0") < 0 {
   323  		return nil
   324  	}
   325  
   326  	if cr.Status.Status != api.AppStateReady && !r.invalidPasswordApplied(cr.Status) {
   327  		return nil
   328  	}
   329  
   330  	user := &users.SysUser{
   331  		Name:  users.Replication,
   332  		Pass:  string(secrets.Data[users.Replication]),
   333  		Hosts: []string{"%"},
   334  	}
   335  
   336  	if cr.Status.PXC.Ready > 0 {
   337  		err := r.manageReplicationUser(ctx, cr, secrets, internalSecrets)
   338  		if err != nil {
   339  			return errors.Wrap(err, "manage replication user")
   340  		}
   341  
   342  		if err := r.updateUserPassExpirationPolicy(ctx, cr, internalSecrets, user); err != nil {
   343  			return err
   344  		}
   345  	}
   346  
   347  	if cr.Status.Status != api.AppStateReady && !r.invalidPasswordApplied(cr.Status) {
   348  		return nil
   349  	}
   350  
   351  	if bytes.Equal(secrets.Data[user.Name], internalSecrets.Data[user.Name]) {
   352  		return nil
   353  	}
   354  
   355  	log.Info("Password changed, updating user", "user", user.Name)
   356  
   357  	err := r.updateUserPassWithoutDP(cr, secrets, internalSecrets, user)
   358  	if err != nil {
   359  		return errors.Wrap(err, "update replication users pass")
   360  	}
   361  	log.Info("User password updated", "user", user.Name)
   362  
   363  	if err := r.updateMySQLInitFile(ctx, cr, internalSecrets, user); err != nil {
   364  		return errors.Wrap(err, "update mysql init file")
   365  	}
   366  
   367  	orig := internalSecrets.DeepCopy()
   368  	internalSecrets.Data[user.Name] = secrets.Data[user.Name]
   369  	err = r.client.Patch(context.TODO(), internalSecrets, client.MergeFrom(orig))
   370  	if err != nil {
   371  		return errors.Wrap(err, "update internal users secrets replication user password")
   372  	}
   373  	log.Info("Internal secrets updated", "user", user.Name)
   374  
   375  	actions.updateReplicationPass = true
   376  	return nil
   377  }
   378  
   379  func (r *ReconcilePerconaXtraDBCluster) handleProxyadminUserWithoutDP(ctx context.Context, cr *api.PerconaXtraDBCluster, secrets, internalSecrets *corev1.Secret, actions *userUpdateActions) error {
   380  	log := logf.FromContext(ctx)
   381  
   382  	if !cr.Spec.ProxySQLEnabled() {
   383  		return nil
   384  	}
   385  
   386  	user := &users.SysUser{
   387  		Name: users.ProxyAdmin,
   388  		Pass: string(secrets.Data[users.ProxyAdmin]),
   389  	}
   390  
   391  	if bytes.Equal(secrets.Data[user.Name], internalSecrets.Data[user.Name]) {
   392  		return nil
   393  	}
   394  
   395  	if cr.Status.Status != api.AppStateReady && !r.invalidPasswordApplied(cr.Status) {
   396  		return nil
   397  	}
   398  
   399  	if err := r.updateUserPassExpirationPolicy(ctx, cr, internalSecrets, user); err != nil {
   400  		return err
   401  	}
   402  
   403  	log.Info("Password changed, updating user", "user", user.Name)
   404  
   405  	err := r.updateProxyUser(cr, internalSecrets, user)
   406  	if err != nil {
   407  		return errors.Wrap(err, "update Proxy users")
   408  	}
   409  	log.Info("Proxy user updated", "user", user.Name)
   410  
   411  	orig := internalSecrets.DeepCopy()
   412  	internalSecrets.Data[user.Name] = secrets.Data[user.Name]
   413  	err = r.client.Patch(context.TODO(), internalSecrets, client.MergeFrom(orig))
   414  	if err != nil {
   415  		return errors.Wrap(err, "update internal users secrets proxyadmin user password")
   416  	}
   417  	log.Info("Internal secrets updated", "user", user.Name)
   418  
   419  	actions.restartProxy = true
   420  
   421  	return nil
   422  }
   423  
   424  func (r *ReconcilePerconaXtraDBCluster) updateUserPassWithoutDP(cr *api.PerconaXtraDBCluster, secrets, internalSecrets *corev1.Secret, user *users.SysUser) error {
   425  	um, err := getUserManager(cr, internalSecrets)
   426  	if err != nil {
   427  		return err
   428  	}
   429  	defer um.Close()
   430  
   431  	err = um.UpdateUserPassWithoutDP(user)
   432  	if err != nil {
   433  		return errors.Wrap(err, "update user pass")
   434  	}
   435  
   436  	return nil
   437  }