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 }