in oracle/controllers/databasecontroller/database_resources.go [206:320]
func SyncUsers(ctx context.Context, r *DatabaseReconciler, db *v1alpha1.Database, cdbName string, log logr.Logger) error {
log.Info("resources/syncUsers: sync database users requested", "db", db)
r.Recorder.Eventf(db, corev1.EventTypeNormal, k8s.SyncingUser, fmt.Sprintf("Syncing users for database %q", db.Spec.Name))
var userSpecs []*controllers.User
var usernames []string
userVerMap := make(map[string]string)
// Copy pdb admin user version into local map to sync later.
if v, ok := db.Status.UserResourceVersions[pdbAdminUserName]; ok {
userVerMap[pdbAdminUserName] = v
}
for _, user := range db.Spec.Users {
var privs []string
usernames = append(usernames, user.Name)
for _, specPriv := range user.Privileges {
privs = append(privs, string(specPriv))
}
userSpec := &controllers.User{
Name: user.Name,
Privileges: privs,
}
// database_controller.validateSpec has validated the spec earlier;
// So no duplicated validation here.
if user.Password != "" {
userVerMap[user.Name] = user.Password
userSpec.Password = user.Password
lastPwd, ok := db.Status.UserResourceVersions[user.Name]
if ok {
userSpec.LastPassword = lastPwd
}
}
if user.GsmSecretRef != nil {
userVerMap[user.Name] = fmt.Sprintf(gsmResourceVersionString, user.GsmSecretRef.ProjectId, user.GsmSecretRef.SecretId, user.GsmSecretRef.Version)
ref := &controllers.GsmSecretReference{
ProjectId: user.GsmSecretRef.ProjectId,
SecretId: user.GsmSecretRef.SecretId,
Version: user.GsmSecretRef.Version,
}
if lastVer, ok := db.Status.UserResourceVersions[user.Name]; ok {
ref.LastVersion = lastVer
}
userSpec.PasswordGsmSecretRef = ref
}
userSpecs = append(userSpecs, userSpec)
}
req := &controllers.UsersChangedRequest{
PdbName: db.Spec.Name,
UserSpecs: userSpecs,
}
resp, err := controllers.UsersChanged(ctx, r, r.DatabaseClientFactory, db.GetNamespace(), db.Spec.Instance, *req)
if err != nil {
log.Error(err, "resources/syncUsers: failed on UsersChanged gRPC call")
return err
}
if resp.Changed {
db.Status.Phase = commonv1alpha1.DatabaseUpdating
db.Status.Conditions = k8s.Upsert(db.Status.Conditions, k8s.UserReady, v1.ConditionFalse, k8s.SyncInProgress, "")
if err := r.Status().Update(ctx, db); err != nil {
return err
}
log.Info("resources/syncUsers: update database users requested", "CDB", cdbName, "PDB", db.Spec.Name)
req := &controllers.UpdateUsersRequest{
PdbName: db.Spec.Name,
UserSpecs: userSpecs,
}
if err := controllers.UpdateUsers(ctx, r, r.DatabaseClientFactory, db.GetNamespace(), db.Spec.Instance, *req); err != nil {
log.Error(err, "resources/syncUsers: failed on UpdateUser gRPC call")
return err
}
log.Info("resources/syncUsers: update database users done", "CDB", cdbName, "PDB", db.Spec.Name)
}
log.Info("resources/syncUsers: sync database users done", "CDB", cdbName, "PDB", db.Spec.Name)
userReady := &v1.Condition{
Type: k8s.UserReady,
Status: v1.ConditionTrue,
Reason: k8s.SyncComplete,
Message: "",
}
if len(resp.Suppressed) != 0 {
userReady.Status = v1.ConditionFalse
userReady.Reason = k8s.UserOutOfSync
var msg []string
for _, u := range resp.Suppressed {
if u.SuppressType == controllers.UsersChangedResponse_DELETE {
msg = append(msg, fmt.Sprintf("User %q not defined in database spec, "+
"supposed to be deleted. suppressed SQL %q. Fix by deleting the user in DB or updating DB spec to include the user", u.UserName, u.Sql))
} else if u.SuppressType == controllers.UsersChangedResponse_CREATE {
msg = append(msg, fmt.Sprintf("User %q cannot be created, "+
"password is not provided. Fix by creating the user in DB or updating DB spec to include password", u.UserName))
}
}
userReady.Message = strings.Join(msg, ".")
}
if k8s.ConditionStatusEquals(userReady, v1.ConditionTrue) {
r.Recorder.Eventf(db, corev1.EventTypeNormal, k8s.SyncedUser, fmt.Sprintf("Synced users for database %q", db.Spec.Name))
} else {
r.Recorder.Eventf(db, corev1.EventTypeWarning, k8s.FailedToSyncUser, fmt.Sprintf("Failed to sync users for database %q, %s", db.Spec.Name, userReady.Message))
}
db.Status.Conditions = k8s.Upsert(db.Status.Conditions, userReady.Type, userReady.Status, userReady.Reason, userReady.Message)
db.Status.UserResourceVersions = userVerMap
db.Status.UserNames = usernames[0:integer.IntMin(3, len(usernames))]
if len(usernames) > 3 {
db.Status.UserNames = append(db.Status.UserNames, "...")
}
r.updateIsChangeApplied(ctx, db)
if err := r.Status().Update(ctx, db); err != nil {
return err
}
return nil
}