X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/36f730574cf6d5f720656de6a102963af5e15cab..cf315eea954e291f56999eb5dcdec559a08e70c0:/tools/sync-users/sync-users.go diff --git a/tools/sync-users/sync-users.go b/tools/sync-users/sync-users.go index 001014255d..626d9d0422 100644 --- a/tools/sync-users/sync-users.go +++ b/tools/sync-users/sync-users.go @@ -123,8 +123,10 @@ func ParseFlags(cfg *ConfigParams) error { // Input file as a required positional argument if flags.NArg() == 0 { return fmt.Errorf("please provide a path to an input file") + } else if flags.NArg() > 1 { + return fmt.Errorf("please provide just one input file argument") } - srcPath := &os.Args[flags.NFlag()+1] + srcPath := &os.Args[len(os.Args)-1] // Validations if *srcPath == "" { @@ -222,6 +224,7 @@ func doMain(cfg *ConfigParams) error { allUsers := make(map[string]arvados.User) userIDToUUID := make(map[string]string) // Index by email or username dupedEmails := make(map[string][]arvados.User) + emptyUserIDs := []string{} processedUsers := make(map[string]bool) results, err := GetAll(cfg.Client, "users", arvados.ResourceListParams{}, &UserList{}) if err != nil { @@ -246,7 +249,11 @@ func doMain(cfg *ConfigParams) error { return err } if uID == "" { - return fmt.Errorf("%s is empty for user with uuid %q", cfg.UserID, u.UUID) + if u.UUID != cfg.AnonUserUUID && u.UUID != cfg.SysUserUUID { + emptyUserIDs = append(emptyUserIDs, u.UUID) + log.Printf("Empty %s found in user %s - ignoring", cfg.UserID, u.UUID) + } + continue } if cfg.CaseInsensitive { uID = strings.ToLower(uID) @@ -327,7 +334,7 @@ func doMain(cfg *ConfigParams) error { log.Printf("User update successes: %d, skips: %d, failures: %d", len(updatesSucceeded), len(updatesSkipped), len(updatesFailed)) - // Report duplicated emails detection + var errors []string if len(dupedEmails) > 0 { emails := make([]string, len(dupedEmails)) i := 0 @@ -335,7 +342,13 @@ func doMain(cfg *ConfigParams) error { emails[i] = e i++ } - return fmt.Errorf("skipped %d duplicated email address(es) in the cluster's local user list: %v", len(dupedEmails), emails) + errors = append(errors, fmt.Sprintf("skipped %d duplicated email address(es) in the cluster's local user list: %v", len(dupedEmails), emails)) + } + if len(emptyUserIDs) > 0 { + errors = append(errors, fmt.Sprintf("skipped %d user account(s) with empty %s: %v", len(emptyUserIDs), cfg.UserID, emptyUserIDs)) + } + if len(errors) > 0 { + return fmt.Errorf("%s", strings.Join(errors, "\n")) } return nil @@ -359,6 +372,12 @@ type userRecord struct { Admin bool } +func needsUpdating(user arvados.User, record userRecord) bool { + userData := userRecord{"", user.FirstName, user.LastName, user.IsActive, user.IsAdmin} + recordData := userRecord{"", record.FirstName, record.LastName, record.Active, record.Active && record.Admin} + return userData != recordData +} + // ProcessRecord creates or updates a user based on the given record func ProcessRecord(cfg *ConfigParams, record userRecord, userIDToUUID map[string]string, allUsers map[string]arvados.User) (bool, error) { if cfg.Verbose { @@ -372,8 +391,8 @@ func ProcessRecord(cfg *ConfigParams, record userRecord, userIDToUUID map[string // Check if user exists, set its active & admin status. var user arvados.User recordUUID := userIDToUUID[record.UserID] - user, ok := allUsers[recordUUID] - if !ok { + user, found := allUsers[recordUUID] + if !found { if cfg.Verbose { log.Printf("User %q does not exist, creating", record.UserID) } @@ -388,45 +407,45 @@ func ProcessRecord(cfg *ConfigParams, record userRecord, userIDToUUID map[string if err != nil { return false, fmt.Errorf("error creating user %q: %s", record.UserID, err) } - } - if record.Active != user.IsActive { + } else if needsUpdating(user, record) { updateRequired = true if record.Active { - if cfg.Verbose { - log.Printf("User %q is inactive, activating", record.UserID) + if !user.IsActive && cfg.Verbose { + log.Printf("User %q (%s) is inactive, activating", record.UserID, user.UUID) } // Here we assume the 'setup' is done elsewhere if needed. err := UpdateUser(cfg.Client, user.UUID, &user, map[string]string{ - "is_active": wantedActiveStatus, - "is_admin": wantedAdminStatus, // Just in case it needs to be changed. + "first_name": record.FirstName, + "last_name": record.LastName, + "is_active": wantedActiveStatus, + "is_admin": wantedAdminStatus, }) if err != nil { return false, fmt.Errorf("error updating user %q: %s", record.UserID, err) } } else { - if cfg.Verbose { - log.Printf("User %q is active, deactivating", record.UserID) + fnChanged := user.FirstName != record.FirstName + lnChanged := user.LastName != record.LastName + if fnChanged || lnChanged { + err := UpdateUser(cfg.Client, user.UUID, &user, map[string]string{ + "first_name": record.FirstName, + "last_name": record.LastName, + }) + if err != nil { + return false, fmt.Errorf("error updating user %q: %s", record.UserID, err) + } } - err := UnsetupUser(cfg.Client, user.UUID, &user) - if err != nil { - return false, fmt.Errorf("error deactivating user %q: %s", record.UserID, err) + if user.IsActive { + if cfg.Verbose { + log.Printf("User %q is active, deactivating", record.UserID) + } + err := UnsetupUser(cfg.Client, user.UUID, &user) + if err != nil { + return false, fmt.Errorf("error deactivating user %q: %s", record.UserID, err) + } } } } - // Inactive users cannot be admins. - if user.IsActive && record.Admin != user.IsAdmin { - if cfg.Verbose { - log.Printf("User %q is active, changing admin status to %v", record.UserID, record.Admin) - } - updateRequired = true - err := UpdateUser(cfg.Client, user.UUID, &user, map[string]string{ - "is_admin": wantedAdminStatus, - }) - if err != nil { - return false, fmt.Errorf("error updating user %q: %s", record.UserID, err) - } - } - allUsers[record.UserID] = user if createRequired { log.Printf("Created user %q", record.UserID) }