Add default org logic to OrganizationsStore

Update resource handlers to appropriate consume default organization IDs
pull/2219/head
Michael Desa 2017-11-02 16:47:45 -04:00
parent 7f7674d829
commit 3370774e8f
14 changed files with 445 additions and 54 deletions

View File

@ -16,6 +16,11 @@ var _ chronograf.OrganizationsStore = &OrganizationsStore{}
// OrganizationsBucket is the bucket where organizations are stored.
var OrganizationsBucket = []byte("OrganizationsV1")
// DefaultOrganizationID is the ID of the default organization.
const DefaultOrganizationID uint64 = 0
const DefaultOrganizationName string = "__default"
const DefaultOrganizationRole string = "member"
// OrganizationsStore uses bolt to store and retrieve Organizations
type OrganizationsStore struct {
client *Client
@ -23,10 +28,15 @@ type OrganizationsStore struct {
// Migrate sets the default organization at runtime
func (s *OrganizationsStore) Migrate(ctx context.Context) error {
return s.CreateDefault(ctx)
}
// CreateDefault does a findOrCreate on the default organization
func (s *OrganizationsStore) CreateDefault(ctx context.Context) error {
o := chronograf.Organization{
ID: 0,
Name: "__default",
DefaultRole: "member",
ID: DefaultOrganizationID,
Name: DefaultOrganizationName,
DefaultRole: DefaultOrganizationRole,
}
return s.client.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(OrganizationsBucket)
@ -54,6 +64,19 @@ func (s *OrganizationsStore) nameIsUnique(ctx context.Context, name string) bool
}
}
// DefaultOrganizationID returns the ID of the default organization
func (s *OrganizationsStore) DefaultOrganization(ctx context.Context) (*chronograf.Organization, error) {
var org chronograf.Organization
if err := s.client.db.View(func(tx *bolt.Tx) error {
v := tx.Bucket(OrganizationsBucket).Get(u64tob(DefaultOrganizationID))
return internal.UnmarshalOrganization(v, &org)
}); err != nil {
return nil, err
}
return &org, nil
}
// Add creates a new Organization in the OrganizationsStore
func (s *OrganizationsStore) Add(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) {
if !s.nameIsUnique(ctx, o.Name) {

View File

@ -7,6 +7,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/bolt"
)
var orgCmpOptions = cmp.Options{
@ -463,3 +464,71 @@ func TestOrganizationsStore_Add(t *testing.T) {
}
}
}
func TestOrganizationsStore_DefaultOrganization(t *testing.T) {
type fields struct {
orgs []chronograf.Organization
}
type args struct {
ctx context.Context
}
tests := []struct {
name string
fields fields
args args
want *chronograf.Organization
wantErr bool
}{
{
name: "Get Default Organization",
fields: fields{
orgs: []chronograf.Organization{
{
Name: "The Good Place",
},
},
},
args: args{
ctx: context.Background(),
},
want: &chronograf.Organization{
ID: bolt.DefaultOrganizationID,
Name: bolt.DefaultOrganizationName,
DefaultRole: bolt.DefaultOrganizationRole,
},
wantErr: false,
},
}
for _, tt := range tests {
client, err := NewTestClient()
if err != nil {
t.Fatal(err)
}
if err := client.Open(context.TODO()); err != nil {
t.Fatal(err)
}
defer client.Close()
s := client.OrganizationsStore
for _, org := range tt.fields.orgs {
_, err = s.Add(tt.args.ctx, &org)
if err != nil {
t.Fatal(err)
}
}
got, err := s.DefaultOrganization(tt.args.ctx)
if (err != nil) != tt.wantErr {
t.Errorf("%q. OrganizationsStore.Update() error = %v, wantErr %v", tt.name, err, tt.wantErr)
}
if tt.want == nil {
continue
}
if diff := cmp.Diff(got, tt.want, orgCmpOptions...); diff != "" {
t.Errorf("%q. OrganizationsStore.Update():\n-got/+want\ndiff %s", tt.name, diff)
}
}
}

View File

@ -20,19 +20,20 @@ import (
// General errors.
const (
ErrUpstreamTimeout = Error("request to backend timed out")
ErrSourceNotFound = Error("source not found")
ErrServerNotFound = Error("server not found")
ErrLayoutNotFound = Error("layout not found")
ErrDashboardNotFound = Error("dashboard not found")
ErrUserNotFound = Error("user not found")
ErrOrganizationNotFound = Error("organization not found")
ErrLayoutInvalid = Error("layout is invalid")
ErrAlertNotFound = Error("alert not found")
ErrAuthentication = Error("user not authenticated")
ErrUninitialized = Error("client uninitialized. Call Open() method")
ErrInvalidAxis = Error("Unexpected axis in cell. Valid axes are 'x', 'y', and 'y2'")
ErrOrganizationNameTaken = Error("organization name is taken")
ErrUpstreamTimeout = Error("request to backend timed out")
ErrSourceNotFound = Error("source not found")
ErrServerNotFound = Error("server not found")
ErrLayoutNotFound = Error("layout not found")
ErrDashboardNotFound = Error("dashboard not found")
ErrUserNotFound = Error("user not found")
ErrOrganizationNotFound = Error("organization not found")
ErrLayoutInvalid = Error("layout is invalid")
ErrAlertNotFound = Error("alert not found")
ErrAuthentication = Error("user not authenticated")
ErrUninitialized = Error("client uninitialized. Call Open() method")
ErrInvalidAxis = Error("Unexpected axis in cell. Valid axes are 'x', 'y', and 'y2'")
ErrOrganizationNameTaken = Error("organization name is taken")
ErrCannotDeleteDefaultOrganization = Error("cannot delete default organization")
)
// Error is a domain error encountered while processing chronograf requests
@ -806,4 +807,8 @@ type OrganizationsStore interface {
Get(context.Context, OrganizationQuery) (*Organization, error)
// Update updates an Organization in the OrganizationsStore
Update(context.Context, *Organization) error
// CreateDefault creates the default organization
CreateDefault(ctx context.Context) error
// DefaultOrganization returns the DefaultOrganization
DefaultOrganization(ctx context.Context) (*Organization, error)
}

View File

@ -9,11 +9,21 @@ import (
var _ chronograf.OrganizationsStore = &OrganizationsStore{}
type OrganizationsStore struct {
AllF func(context.Context) ([]chronograf.Organization, error)
AddF func(context.Context, *chronograf.Organization) (*chronograf.Organization, error)
DeleteF func(context.Context, *chronograf.Organization) error
GetF func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error)
UpdateF func(context.Context, *chronograf.Organization) error
AllF func(context.Context) ([]chronograf.Organization, error)
AddF func(context.Context, *chronograf.Organization) (*chronograf.Organization, error)
DeleteF func(context.Context, *chronograf.Organization) error
GetF func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error)
UpdateF func(context.Context, *chronograf.Organization) error
CreateDefaultF func(context.Context) error
DefaultOrganizationF func(context.Context) (*chronograf.Organization, error)
}
func (s *OrganizationsStore) CreateDefault(ctx context.Context) error {
return s.CreateDefaultF(ctx)
}
func (s *OrganizationsStore) DefaultOrganization(ctx context.Context) (*chronograf.Organization, error) {
return s.DefaultOrganizationF(ctx)
}
func (s *OrganizationsStore) Add(ctx context.Context, o *chronograf.Organization) (*chronograf.Organization, error) {

View File

@ -12,6 +12,14 @@ var _ chronograf.OrganizationsStore = &OrganizationsStore{}
type OrganizationsStore struct{}
func (s *OrganizationsStore) CreateDefault(context.Context) error {
return fmt.Errorf("failed to add organization")
}
func (s *OrganizationsStore) DefaultOrganization(context.Context) (*chronograf.Organization, error) {
return nil, fmt.Errorf("failed to retrieve default organization")
}
func (s *OrganizationsStore) All(context.Context) ([]chronograf.Organization, error) {
return nil, fmt.Errorf("no organizations found")
}

View File

@ -88,7 +88,12 @@ func AuthorizedUser(
// This is as if the user was logged into the default organization
if p.Organization == "" {
p.Organization = "0"
defaultOrg, err := store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, logger)
return
}
p.Organization = fmt.Sprintf("%d", defaultOrg.ID)
}
// validate that the organization exists

View File

@ -117,6 +117,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -164,6 +170,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -211,6 +223,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -258,6 +276,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -305,6 +329,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -352,6 +382,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -399,6 +435,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -446,6 +488,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -493,6 +541,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -535,6 +589,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -577,6 +637,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -619,6 +685,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -665,6 +737,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -757,6 +835,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -804,6 +888,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -851,6 +941,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -898,6 +994,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -946,6 +1048,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -994,6 +1102,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -1042,6 +1156,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -1090,6 +1210,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -1137,6 +1263,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -1180,6 +1312,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -1226,6 +1364,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -1273,6 +1417,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -1330,6 +1480,12 @@ func TestAuthorizedUser(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")

View File

@ -87,18 +87,24 @@ func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) {
// NewDashboard creates and returns a new dashboard object
func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) {
var dashboard chronograf.Dashboard
var err error
if err := json.NewDecoder(r.Body).Decode(&dashboard); err != nil {
invalidJSON(w, s.Logger)
return
}
if err := ValidDashboardRequest(&dashboard); err != nil {
ctx := r.Context()
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
if err := ValidDashboardRequest(&dashboard, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
invalidData(w, err, s.Logger)
return
}
var err error
ctx := r.Context()
if dashboard, err = s.Store.Dashboards(ctx).Add(r.Context(), dashboard); err != nil {
msg := fmt.Errorf("Error storing dashboard %v: %v", dashboard, err)
unknownErrorWithMessage(w, msg, s.Logger)
@ -155,7 +161,13 @@ func (s *Service) ReplaceDashboard(w http.ResponseWriter, r *http.Request) {
}
req.ID = id
if err := ValidDashboardRequest(&req); err != nil {
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
if err := ValidDashboardRequest(&req, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
invalidData(w, err, s.Logger)
return
}
@ -197,7 +209,12 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {
if req.Name != "" {
orig.Name = req.Name
} else if len(req.Cells) > 0 {
if err := ValidDashboardRequest(&req); err != nil {
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
if err := ValidDashboardRequest(&req, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
invalidData(w, err, s.Logger)
return
}
@ -218,9 +235,9 @@ func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {
}
// ValidDashboardRequest verifies that the dashboard cells have a query
func ValidDashboardRequest(d *chronograf.Dashboard) error {
func ValidDashboardRequest(d *chronograf.Dashboard, defaultOrgID string) error {
if d.Organization == "" {
d.Organization = "0"
d.Organization = defaultOrgID
}
for i, c := range d.Cells {
if err := ValidDashboardCellRequest(&c); err != nil {

View File

@ -192,7 +192,8 @@ func TestValidDashboardRequest(t *testing.T) {
},
}
for _, tt := range tests {
err := ValidDashboardRequest(&tt.d)
// TODO(desa): this Okay?
err := ValidDashboardRequest(&tt.d, "0")
if (err != nil) != tt.wantErr {
t.Errorf("%q. ValidDashboardRequest() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue

View File

@ -20,13 +20,13 @@ type postKapacitorRequest struct {
Organization string `json:"organization"` // Organization is the organization ID that resource belongs to
}
func (p *postKapacitorRequest) Valid() error {
func (p *postKapacitorRequest) Valid(defaultOrgID string) error {
if p.Name == nil || p.URL == nil {
return fmt.Errorf("name and url required")
}
if p.Organization == "" {
p.Organization = "0"
p.Organization = defaultOrgID
}
url, err := url.ParseRequestURI(*p.URL)
@ -78,7 +78,14 @@ func (s *Service) NewKapacitor(w http.ResponseWriter, r *http.Request) {
invalidJSON(w, s.Logger)
return
}
if err := req.Valid(); err != nil {
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
if err := req.Valid(fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
invalidData(w, err, s.Logger)
return
}

View File

@ -52,18 +52,24 @@ func newLayoutResponse(layout chronograf.Layout) layoutResponse {
// NewLayout adds a valid layout to store.
func (s *Service) NewLayout(w http.ResponseWriter, r *http.Request) {
var layout chronograf.Layout
var err error
if err := json.NewDecoder(r.Body).Decode(&layout); err != nil {
invalidJSON(w, s.Logger)
return
}
if err := ValidLayoutRequest(layout); err != nil {
ctx := r.Context()
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
if err := ValidLayoutRequest(layout, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
invalidData(w, err, s.Logger)
return
}
var err error
ctx := r.Context()
if layout, err = s.Store.Layouts(ctx).Add(r.Context(), layout); err != nil {
msg := fmt.Errorf("Error storing layout %v: %v", layout, err)
unknownErrorWithMessage(w, msg, s.Logger)
@ -169,7 +175,13 @@ func (s *Service) UpdateLayout(w http.ResponseWriter, r *http.Request) {
}
req.ID = id
if err := ValidLayoutRequest(req); err != nil {
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
if err := ValidLayoutRequest(req, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
invalidData(w, err, s.Logger)
return
}
@ -185,13 +197,13 @@ func (s *Service) UpdateLayout(w http.ResponseWriter, r *http.Request) {
}
// ValidLayoutRequest checks if the layout has valid application, measurement and cells.
func ValidLayoutRequest(l chronograf.Layout) error {
func ValidLayoutRequest(l chronograf.Layout, defaultOrgID string) error {
if l.Application == "" || l.Measurement == "" || len(l.Cells) == 0 {
return fmt.Errorf("app, measurement, and cells required")
}
if l.Organization == "" {
l.Organization = "0"
l.Organization = defaultOrgID
}
for _, c := range l.Cells {

View File

@ -67,10 +67,6 @@ func getValidPrincipal(ctx context.Context) (oauth2.Principal, error) {
if p.Issuer == "" {
return oauth2.Principal{}, fmt.Errorf("Token not found")
}
// TODO(desa): make this default org
if p.Organization == "" {
p.Organization = "0"
}
return p, nil
}
@ -108,18 +104,27 @@ func (s *Service) MeOrganization(auth oauth2.Authenticator) func(http.ResponseWr
return
}
// validate that user belongs to organization
ctx = context.WithValue(ctx, organizations.ContextKey, req.Organization)
p, err := getValidPrincipal(ctx)
if err != nil {
invalidData(w, err, s.Logger)
return
}
if p.Organization == "" {
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
p.Organization = fmt.Sprintf("%d", defaultOrg.ID)
}
scheme, err := getScheme(ctx)
if err != nil {
invalidData(w, err, s.Logger)
return
}
// validate that user belongs to organization
ctx = context.WithValue(ctx, organizations.ContextKey, req.Organization)
_, err = s.Store.Users(ctx).Get(ctx, chronograf.UserQuery{
Name: &p.Subject,
Provider: &p.Issuer,
@ -168,9 +173,19 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
invalidData(w, err, s.Logger)
return
}
ctx = context.WithValue(ctx, organizations.ContextKey, p.Organization)
ctx = context.WithValue(ctx, SuperAdminKey, true)
if p.Organization == "" {
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
p.Organization = fmt.Sprintf("%d", defaultOrg.ID)
}
usr, err := s.Store.Users(ctx).Get(ctx, chronograf.UserQuery{
Name: &p.Subject,
Provider: &p.Issuer,
@ -218,6 +233,12 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
return
}
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
// Because we didnt find a user, making a new one
user := &chronograf.User{
Name: p.Subject,
@ -230,7 +251,7 @@ func (s *Service) Me(w http.ResponseWriter, r *http.Request) {
{
Name: MemberRoleName,
// This is the ID of the default organization
Organization: "0",
Organization: fmt.Sprintf("%d", defaultOrg.ID),
},
},
SuperAdmin: s.firstUser(),

View File

@ -48,6 +48,12 @@ func TestService_Me(t *testing.T) {
UseAuth: true,
Logger: log.New(log.DebugLevel),
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
@ -94,6 +100,12 @@ func TestService_Me(t *testing.T) {
UseAuth: true,
Logger: log.New(log.DebugLevel),
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
@ -138,6 +150,12 @@ func TestService_Me(t *testing.T) {
fields: fields{
UseAuth: true,
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
@ -291,6 +309,12 @@ func TestService_MeOrganizations(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -345,6 +369,12 @@ func TestService_MeOrganizations(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -391,6 +421,12 @@ func TestService_MeOrganizations(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
if q.ID == nil {
return nil, fmt.Errorf("Invalid organization query: missing ID")
@ -446,6 +482,12 @@ func TestService_MeOrganizations(t *testing.T) {
},
},
OrganizationsStore: &mocks.OrganizationsStore{
DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
return &chronograf.Organization{
ID: 0,
Name: "The Bad Place",
}, nil
},
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
return nil, chronograf.ErrOrganizationNotFound
},
@ -468,8 +510,6 @@ func TestService_MeOrganizations(t *testing.T) {
UsersStore: tt.fields.UsersStore,
OrganizationsStore: tt.fields.OrganizationsStore,
},
//UsersStore: tt.fields.UsersStore,
//OrganizationUsersStore: tt.fields.OrganizationUsersStore,
Logger: tt.fields.Logger,
UseAuth: tt.fields.UseAuth,
}

View File

@ -68,7 +68,14 @@ func (s *Service) NewSource(w http.ResponseWriter, r *http.Request) {
return
}
if err := ValidSourceRequest(src); err != nil {
ctx := r.Context()
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
if err := ValidSourceRequest(src, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
invalidData(w, err, s.Logger)
return
}
@ -78,7 +85,6 @@ func (s *Service) NewSource(w http.ResponseWriter, r *http.Request) {
src.Telegraf = "telegraf"
}
ctx := r.Context()
dbType, err := s.tsdbType(ctx, &src)
if err != nil {
Error(w, http.StatusBadRequest, "Error contacting source", s.Logger)
@ -254,7 +260,13 @@ func (s *Service) UpdateSource(w http.ResponseWriter, r *http.Request) {
src.Telegraf = req.Telegraf
}
if err := ValidSourceRequest(src); err != nil {
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
unknownErrorWithMessage(w, err, s.Logger)
return
}
if err := ValidSourceRequest(src, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
invalidData(w, err, s.Logger)
return
}
@ -275,7 +287,7 @@ func (s *Service) UpdateSource(w http.ResponseWriter, r *http.Request) {
}
// ValidSourceRequest checks if name, url and type are valid
func ValidSourceRequest(s chronograf.Source) error {
func ValidSourceRequest(s chronograf.Source, defaultOrgID string) error {
// Name and URL areq required
if s.URL == "" {
return fmt.Errorf("url required")
@ -288,7 +300,7 @@ func ValidSourceRequest(s chronograf.Source) error {
}
if s.Organization == "" {
s.Organization = "0"
s.Organization = defaultOrgID
}
url, err := url.ParseRequestURI(s.URL)
@ -319,8 +331,13 @@ func (s *Service) HandleNewSources(ctx context.Context, input string) error {
return err
}
defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
if err != nil {
return err
}
for _, sk := range srcsKaps {
if err := ValidSourceRequest(sk.Source); err != nil {
if err := ValidSourceRequest(sk.Source, fmt.Sprintf("%d", defaultOrg.ID)); err != nil {
return err
}
// Add any new sources and kapacitors as specified via server flag