CLI: Provide the list of admins if the admin with the default ID was not found (#92217)

* Provide the list of admins if the admin with the default ID was not found

* Clean up

* Update docs

* Update docs/sources/cli.md

Co-authored-by: Dan Cech <dcech@grafana.com>

* Update pkg/cmd/grafana-cli/commands/reset_password_command.go

Co-authored-by: Dan Cech <dcech@grafana.com>

* Lint

---------

Co-authored-by: Dan Cech <dcech@grafana.com>
This commit is contained in:
Misi 2024-08-27 16:01:33 +02:00 committed by GitHub
parent a884e03dc5
commit a3d688c8ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 83 additions and 3 deletions

View File

@ -211,7 +211,7 @@ grafana cli admin
### Reset admin password
`grafana cli admin reset-admin-password <new password>` resets the password for the admin user using the CLI. You might need to do this if you lose the admin password.
`grafana cli admin reset-admin-password <new password>` resets the password for the admin user using the CLI. You might need to do this if you lose the admin password. By default, this command uses the default ID of the admin user, which is 1. If you know the ID of the admin user, you can use the `--user-id` flag to specify the user ID. If the `--user-id` flag is not specified and the command cannot find the admin user, it returns the list of current admin users' username and ID. From that list you can determine the ID of the admin user and run the command again with the `--user-id` flag.
If there are two flags being used to set the homepath and the config file path, then running the command returns this error:
@ -227,6 +227,14 @@ If you have not lost the admin password, we recommend that you change the user p
If you need to set the password in a script, then you can use the [Grafana User API]({{< relref "./developers/http_api/user/#change-password" >}}).
#### Reset admin password
If you installed Grafana using Homebrew, you can reset the admin password using the following command:
```bash
/opt/homebrew/opt/grafana/bin/grafana cli --config /opt/homebrew/etc/grafana/grafana.ini --homepath /opt/homebrew/opt/grafana/share/grafana --configOverrides cfg:default.paths.data=/opt/homebrew/var/lib/grafana admin reset-admin-password <new password>
```
### Migrate data and encrypt passwords
`data-migration` runs a script that migrates or cleans up data in your database.

View File

@ -45,6 +45,22 @@ To install Grafana on macOS using Homebrew, complete the following steps:
brew services start grafana
```
### Using the Grafana CLI with Homebrew
To use the Grafana CLI with Homebrew, you need to append the home path, the config file path and - based on the command - some other configurations to the `cli` command:
For `admin` commands, you need to append the `--configOverrides cfg:default.paths.data=/opt/homebrew/var/lib/grafana` configuration. Example:
```bash
/opt/homebrew/opt/grafana/bin/grafana cli --config /opt/homebrew/etc/grafana/grafana.ini --homepath /opt/homebrew/opt/grafana/share/grafana --configOverrides cfg:default.paths.data=/opt/homebrew/var/lib/grafana admin reset-admin-password <new password>
```
For `plugins` commands, you need to append the `--pluginsDir /opt/homebrew/var/lib/grafana/plugins` configuration. Example:
```bash
/opt/homebrew/opt/grafana/bin/grafana cli --config /opt/homebrew/etc/grafana/grafana.ini --homepath /opt/homebrew/opt/grafana/share/grafana --pluginsDir "/opt/homebrew/var/lib/grafana/plugins" plugins install <plugin-id>
```
## Install standalone macOS binaries
To install Grafana on macOS using the standalone binaries, complete the following steps:

View File

@ -3,6 +3,7 @@ package commands
import (
"bufio"
"context"
"errors"
"fmt"
"os"
@ -16,6 +17,11 @@ import (
const DefaultAdminUserId = 1
var (
ErrMustBeAdmin = fmt.Errorf("reset-admin-password can only be used to reset an admin user account")
ErrAdminCannotBeFound = errors.New("admin user cannot be found")
)
func resetPasswordCommand(c utils.CommandLine, runner server.Runner) error {
var newPassword user.Password
adminId := int64(c.Int("user-id"))
@ -44,15 +50,35 @@ func resetPasswordCommand(c utils.CommandLine, runner server.Runner) error {
logger.Infof("\n")
logger.Infof("Admin password changed successfully %s", color.GreenString("✔"))
}
return err
if errors.Is(err, ErrAdminCannotBeFound) {
logger.Infof("\n")
logger.Infof("Admin user cannot be found %s. \n", color.RedString("✘"))
admins, err := listAdminUsers(runner.UserService)
if err != nil {
return fmt.Errorf("failed to list admin users: %w", err)
}
logger.Infof("\n")
logger.Infof("Please try to run the command again specifying a user-id (--user-id) from the list below:\n")
for _, u := range admins {
logger.Infof("\t Username: %s ID: %d\n", u.Login, u.ID)
}
}
return nil
}
func resetPassword(adminId int64, password user.Password, userSvc user.Service) error {
userQuery := user.GetUserByIDQuery{ID: adminId}
usr, err := userSvc.GetByID(context.Background(), &userQuery)
if err != nil {
if errors.Is(err, user.ErrUserNotFound) {
return ErrAdminCannotBeFound
}
return fmt.Errorf("could not read user from database. Error: %v", err)
}
if !usr.IsAdmin {
return ErrMustBeAdmin
}
@ -64,4 +90,34 @@ func resetPassword(adminId int64, password user.Password, userSvc user.Service)
return nil
}
var ErrMustBeAdmin = fmt.Errorf("reset-admin-password can only be used to reset an admin user account")
func listAdminUsers(userSvc user.Service) ([]*user.UserSearchHitDTO, error) {
searchAdminsQuery := user.SearchUsersQuery{
Filters: []user.Filter{&adminFilter{}},
SignedInUser: &user.SignedInUser{
Permissions: map[int64]map[string][]string{0: {"users:read": {"global.users:*"}}},
},
}
admins, err := userSvc.Search(context.Background(), &searchAdminsQuery)
if err != nil {
return nil, fmt.Errorf("could not read user from database. Error: %v", err)
}
return admins.Users, nil
}
type adminFilter struct{}
func (f *adminFilter) WhereCondition() *user.WhereCondition {
return &user.WhereCondition{
Condition: "is_admin = 1",
}
}
func (f *adminFilter) JoinCondition() *user.JoinCondition {
return nil
}
func (f *adminFilter) InCondition() *user.InCondition {
return nil
}