influxdb/chronograf/influx/users.go

231 lines
5.2 KiB
Go
Raw Normal View History

package influx
import (
"context"
2017-02-18 01:58:39 +00:00
"encoding/json"
"fmt"
"github.com/influxdata/influxdb/chronograf"
)
2017-02-19 06:54:52 +00:00
// Add a new User in InfluxDB
2017-02-18 01:58:39 +00:00
func (c *Client) Add(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
_, err := c.Query(ctx, chronograf.Query{
2017-02-19 06:54:52 +00:00
Command: fmt.Sprintf(`CREATE USER "%s" WITH PASSWORD '%s'`, u.Name, u.Passwd),
2017-02-18 01:58:39 +00:00
})
if err != nil {
return nil, err
}
2017-03-10 20:53:30 +00:00
for _, p := range u.Permissions {
if err := c.grantPermission(ctx, u.Name, p); err != nil {
return nil, err
}
}
return c.Get(ctx, chronograf.UserQuery{Name: &u.Name})
2017-02-18 01:58:39 +00:00
}
2017-02-17 21:13:51 +00:00
// Delete the User from InfluxDB
2017-02-18 01:58:39 +00:00
func (c *Client) Delete(ctx context.Context, u *chronograf.User) error {
res, err := c.Query(ctx, chronograf.Query{
2017-02-19 06:54:52 +00:00
Command: fmt.Sprintf(`DROP USER "%s"`, u.Name),
2017-02-18 01:58:39 +00:00
})
if err != nil {
return err
}
// The DROP USER statement puts the error within the results itself
// So, we have to crack open the results to see what happens
octets, err := res.MarshalJSON()
if err != nil {
return err
}
results := make([]struct{ Error string }, 0)
2017-02-19 06:54:52 +00:00
if err := json.Unmarshal(octets, &results); err != nil {
2017-02-18 01:58:39 +00:00
return err
}
// At last, we can check if there are any error strings
for _, r := range results {
if r.Error != "" {
return fmt.Errorf(r.Error)
}
}
return nil
}
// Get retrieves a user if name exists.
func (c *Client) Get(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil {
return nil, fmt.Errorf("query must specify name")
}
2017-02-19 06:54:52 +00:00
users, err := c.showUsers(ctx)
2017-02-18 01:58:39 +00:00
if err != nil {
return nil, err
}
for _, user := range users {
if user.Name == *q.Name {
2017-02-19 06:54:52 +00:00
perms, err := c.userPermissions(ctx, user.Name)
if err != nil {
return nil, err
}
user.Permissions = append(user.Permissions, perms...)
2017-02-18 01:58:39 +00:00
return &user, nil
}
}
return nil, fmt.Errorf("user not found")
}
// Update the user's permissions or roles
2017-02-19 06:54:52 +00:00
func (c *Client) Update(ctx context.Context, u *chronograf.User) error {
2017-02-22 06:36:28 +00:00
// Only allow one type of change at a time. If it is a password
// change then do it and return without any changes to permissions
if u.Passwd != "" {
return c.updatePassword(ctx, u.Name, u.Passwd)
}
user, err := c.Get(ctx, chronograf.UserQuery{Name: &u.Name})
2017-02-18 01:58:39 +00:00
if err != nil {
2017-02-19 06:54:52 +00:00
return err
2017-02-18 01:58:39 +00:00
}
2017-02-19 06:54:52 +00:00
revoke, add := Difference(u.Permissions, user.Permissions)
for _, a := range add {
if err := c.grantPermission(ctx, u.Name, a); err != nil {
return err
}
2017-02-18 01:58:39 +00:00
}
2017-02-19 06:54:52 +00:00
for _, r := range revoke {
if err := c.revokePermission(ctx, u.Name, r); err != nil {
return err
}
}
return nil
}
// All users in influx
func (c *Client) All(ctx context.Context) ([]chronograf.User, error) {
users, err := c.showUsers(ctx)
if err != nil {
2017-02-18 01:58:39 +00:00
return nil, err
}
2017-02-19 06:54:52 +00:00
// For all users we need to look up permissions to add to the user.
2017-02-18 01:58:39 +00:00
for i, user := range users {
perms, err := c.userPermissions(ctx, user.Name)
if err != nil {
return nil, err
}
user.Permissions = append(user.Permissions, perms...)
users[i] = user
}
return users, nil
}
2018-01-09 23:15:12 +00:00
// Num is the number of users in DB
2017-11-30 17:55:59 +00:00
func (c *Client) Num(ctx context.Context) (int, error) {
all, err := c.All(ctx)
if err != nil {
return 0, err
}
return len(all), nil
}
2017-02-19 06:54:52 +00:00
// showUsers runs SHOW USERS InfluxQL command and returns chronograf users.
func (c *Client) showUsers(ctx context.Context) ([]chronograf.User, error) {
2017-02-18 01:58:39 +00:00
res, err := c.Query(ctx, chronograf.Query{
2017-02-19 06:54:52 +00:00
Command: `SHOW USERS`,
2017-02-18 01:58:39 +00:00
})
if err != nil {
return nil, err
}
octets, err := res.MarshalJSON()
if err != nil {
return nil, err
}
results := showResults{}
if err := json.Unmarshal(octets, &results); err != nil {
return nil, err
}
2017-02-19 06:54:52 +00:00
return results.Users(), nil
2017-02-18 01:58:39 +00:00
}
2017-02-19 06:54:52 +00:00
func (c *Client) grantPermission(ctx context.Context, username string, perm chronograf.Permission) error {
query := ToGrant(username, perm)
if query == "" {
return nil
2017-02-18 01:58:39 +00:00
}
2017-02-19 06:54:52 +00:00
_, err := c.Query(ctx, chronograf.Query{
Command: query,
})
return err
2017-02-18 01:58:39 +00:00
}
2017-02-19 06:54:52 +00:00
func (c *Client) revokePermission(ctx context.Context, username string, perm chronograf.Permission) error {
query := ToRevoke(username, perm)
if query == "" {
return nil
2017-02-18 01:58:39 +00:00
}
2017-02-19 06:54:52 +00:00
_, err := c.Query(ctx, chronograf.Query{
Command: query,
})
return err
2017-02-18 01:58:39 +00:00
}
2017-02-19 06:54:52 +00:00
func (c *Client) userPermissions(ctx context.Context, name string) (chronograf.Permissions, error) {
res, err := c.Query(ctx, chronograf.Query{
Command: fmt.Sprintf(`SHOW GRANTS FOR "%s"`, name),
})
if err != nil {
return nil, err
}
octets, err := res.MarshalJSON()
if err != nil {
return nil, err
2017-02-18 01:58:39 +00:00
}
2017-02-19 06:54:52 +00:00
results := showResults{}
if err := json.Unmarshal(octets, &results); err != nil {
return nil, err
}
return results.Permissions(), nil
2017-02-18 01:58:39 +00:00
}
2017-02-22 06:36:28 +00:00
func (c *Client) updatePassword(ctx context.Context, name, passwd string) error {
res, err := c.Query(ctx, chronograf.Query{
Command: fmt.Sprintf(`SET PASSWORD for "%s" = '%s'`, name, passwd),
})
if err != nil {
return err
}
// The SET PASSWORD statements puts the error within the results itself
// So, we have to crack open the results to see what happens
octets, err := res.MarshalJSON()
if err != nil {
return err
}
results := make([]struct{ Error string }, 0)
if err := json.Unmarshal(octets, &results); err != nil {
return err
}
// At last, we can check if there are any error strings
for _, r := range results {
if r.Error != "" {
return fmt.Errorf(r.Error)
}
}
return nil
}