Add Influx OSS implementation of users

pull/101/head
Chris Goller 2017-02-17 19:58:39 -06:00
parent 31276954b3
commit 2d122ef698
1 changed files with 163 additions and 5 deletions

View File

@ -2,23 +2,181 @@ package influx
import (
"context"
"encoding/json"
"fmt"
"github.com/influxdata/chronograf"
)
// Create a new User in InfluxDB
func (c *Client) Add(context.Context, *chronograf.User) (*chronograf.User, error) { return nil, nil }
func (c *Client) Add(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
_, err := c.Query(ctx, chronograf.Query{
Command: fmt.Sprintf(`CREATE USER %s WITH PASSWORD '%s'`, u.Name, u.Passwd),
})
if err != nil {
return nil, err
}
return u, nil
}
// Delete the User from InfluxDB
func (c *Client) Delete(context.Context, *chronograf.User) error { return nil }
func (c *Client) Delete(ctx context.Context, u *chronograf.User) error {
res, err := c.Query(ctx, chronograf.Query{
Command: fmt.Sprintf(`DROP USER %s`, u.Name),
})
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)
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
}
// Get retrieves a user if name exists.
func (c *Client) Get(ctx context.Context, name string) (*chronograf.User, error) {
return nil, nil
users, err := c.All(ctx)
if err != nil {
return nil, err
}
for _, user := range users {
if user.Name == name {
return &user, nil
}
}
return nil, fmt.Errorf("user not found")
}
// Update the user's permissions or roles
func (c *Client) Update(context.Context, *chronograf.User) error { return nil }
// All is all users in influx
func (c *Client) All(context.Context) ([]chronograf.User, error) { return nil, nil }
// All users in influx
func (c *Client) All(ctx context.Context) ([]chronograf.User, error) {
res, err := c.Query(ctx, chronograf.Query{
Command: `SHOW USERS`,
})
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
}
users := results.Users()
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
}
type showResults []struct {
Series []struct {
Values [][]interface{} `json:"values"`
} `json:"series"`
}
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
}
results := showResults{}
if err := json.Unmarshal(octets, &results); err != nil {
return nil, err
}
return results.Permissions(), nil
}
func (r *showResults) Users() []chronograf.User {
res := []chronograf.User{}
for _, u := range *r {
for _, s := range u.Series {
for _, v := range s.Values {
if name, ok := v[0].(string); !ok {
continue
} else if admin, ok := v[1].(bool); !ok {
continue
} else {
c := chronograf.User{
Name: name,
}
if admin {
c.Permissions = adminPerms()
}
res = append(res, c)
}
}
}
}
return res
}
func (r *showResults) Permissions() chronograf.Permissions {
res := []chronograf.Permission{}
for _, u := range *r {
for _, s := range u.Series {
for _, v := range s.Values {
if db, ok := v[0].(string); !ok {
continue
} else if priv, ok := v[1].(string); !ok {
continue
} else {
c := chronograf.Permission{
Name: db,
Allowed: []string{priv},
}
res = append(res, c)
}
}
}
}
return res
}
func adminPerms() chronograf.Permissions {
return []chronograf.Permission{
{
Scope: chronograf.AllScope,
Allowed: []string{"ALL"},
},
}
}