Unscope sources by role

Previously, as a misunderstanding of
https://github.com/influxdata/chronograf/issues/1915 we allowed
sources to be scoped by role within an organization. This was incorrect.
We no longer user the roles implementation of a chronograf.SourcesStore
and just use the organizations store.

We've left the code around a roles SourcesStore in place, since it may
be useful to us in the future. It may be worth removing if it is
determined that this behavior is not desirable.
multitenancy_temp_stash
Michael Desa 2017-11-29 17:32:41 -05:00
parent 95dd68b8ad
commit 9ef1e57934
4 changed files with 11 additions and 441 deletions

View File

@ -451,7 +451,7 @@ type Source struct {
Default bool `json:"default"` // Default specifies the default source for the application Default bool `json:"default"` // Default specifies the default source for the application
Telegraf string `json:"telegraf"` // Telegraf is the db telegraf is written to. By default it is "telegraf" Telegraf string `json:"telegraf"` // Telegraf is the db telegraf is written to. By default it is "telegraf"
Organization string `json:"organization"` // Organization is the organization ID that resource belongs to Organization string `json:"organization"` // Organization is the organization ID that resource belongs to
Role string `json:"role"` // Role is the name of the minimum role that a user must possess to access the resource. Role string `json:"role,omitempty"` // Not Currently Used. Role is the name of the minimum role that a user must possess to access the resource.
} }
// SourcesStore stores connection information for a `TimeSeries` // SourcesStore stores connection information for a `TimeSeries`

View File

@ -6,6 +6,11 @@ import (
"github.com/influxdata/chronograf" "github.com/influxdata/chronograf"
) )
// NOTE:
// This code is currently unused. however, it has been left in place because we aniticipate
// that it may be used in the future. It was originally developed as a misunderstanding of
// https://github.com/influxdata/chronograf/issues/1915
// ensure that SourcesStore implements chronograf.SourceStore // ensure that SourcesStore implements chronograf.SourceStore
var _ chronograf.SourcesStore = &SourcesStore{} var _ chronograf.SourcesStore = &SourcesStore{}

View File

@ -111,10 +111,7 @@ func (s *Store) Sources(ctx context.Context) chronograf.SourcesStore {
return s.SourcesStore return s.SourcesStore
} }
if org, ok := hasOrganizationContext(ctx); ok { if org, ok := hasOrganizationContext(ctx); ok {
store := organizations.NewSourcesStore(s.SourcesStore, org) return organizations.NewSourcesStore(s.SourcesStore, org)
if role, ok := hasRoleContext(ctx); ok {
return roles.NewSourcesStore(store, role)
}
} }
return &noop.SourcesStore{} return &noop.SourcesStore{}

View File

@ -8,7 +8,6 @@ import (
"github.com/influxdata/chronograf" "github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/mocks" "github.com/influxdata/chronograf/mocks"
"github.com/influxdata/chronograf/organizations" "github.com/influxdata/chronograf/organizations"
"github.com/influxdata/chronograf/roles"
) )
func TestStore_SourcesGet(t *testing.T) { func TestStore_SourcesGet(t *testing.T) {
@ -17,7 +16,6 @@ func TestStore_SourcesGet(t *testing.T) {
} }
type args struct { type args struct {
organization string organization string
role string
id int id int
} }
type wants struct { type wants struct {
@ -32,7 +30,7 @@ func TestStore_SourcesGet(t *testing.T) {
wants wants wants wants
}{ }{
{ {
name: "Get viewer source as viewer", name: "Get source",
fields: fields{ fields: fields{
SourcesStore: &mocks.SourcesStore{ SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) { GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
@ -40,26 +38,23 @@ func TestStore_SourcesGet(t *testing.T) {
ID: 1, ID: 1,
Name: "my sweet name", Name: "my sweet name",
Organization: "0", Organization: "0",
Role: "viewer",
}, nil }, nil
}, },
}, },
}, },
args: args{ args: args{
organization: "0", organization: "0",
role: "viewer",
}, },
wants: wants{ wants: wants{
source: chronograf.Source{ source: chronograf.Source{
ID: 1, ID: 1,
Name: "my sweet name", Name: "my sweet name",
Organization: "0", Organization: "0",
Role: "viewer",
}, },
}, },
}, },
{ {
name: "Get viewer source as editor", name: "Get source - no organization specified on context",
fields: fields{ fields: fields{
SourcesStore: &mocks.SourcesStore{ SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) { GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
@ -67,208 +62,6 @@ func TestStore_SourcesGet(t *testing.T) {
ID: 1, ID: 1,
Name: "my sweet name", Name: "my sweet name",
Organization: "0", Organization: "0",
Role: "viewer",
}, nil
},
},
},
args: args{
organization: "0",
role: "editor",
},
wants: wants{
source: chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
},
},
},
{
name: "Get viewer source as admin",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
}, nil
},
},
},
args: args{
organization: "0",
role: "admin",
},
wants: wants{
source: chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
},
},
},
{
name: "Get admin source as viewer",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "admin",
}, nil
},
},
},
args: args{
organization: "0",
role: "viewer",
},
wants: wants{
err: true,
},
},
{
name: "Get editor source as viewer",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "editor",
}, nil
},
},
},
args: args{
organization: "0",
role: "viewer",
},
wants: wants{
err: true,
},
},
{
name: "Get editor source as editor",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "editor",
}, nil
},
},
},
args: args{
organization: "0",
role: "editor",
},
wants: wants{
source: chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "editor",
},
},
},
{
name: "Get editor source as admin",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "editor",
}, nil
},
},
},
args: args{
organization: "0",
role: "admin",
},
wants: wants{
source: chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "editor",
},
},
},
{
name: "Get editor source as viewer",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "editor",
}, nil
},
},
},
args: args{
organization: "0",
role: "viewer",
},
wants: wants{
err: true,
},
},
{
name: "Get admin source as admin",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "admin",
}, nil
},
},
},
args: args{
organization: "0",
role: "admin",
},
wants: wants{
source: chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "admin",
},
},
},
{
name: "No organization or role set on context",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
}, nil }, nil
}, },
}, },
@ -278,69 +71,6 @@ func TestStore_SourcesGet(t *testing.T) {
err: true, err: true,
}, },
}, },
{
name: "Get source as viewer - no organization specified on context",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
}, nil
},
},
},
args: args{
role: "viewer",
},
wants: wants{
err: true,
},
},
{
name: "Get source as editor - no organization specified on context",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
}, nil
},
},
},
args: args{
role: "editor",
},
wants: wants{
err: true,
},
},
{
name: "Get source as admin - no organization specified on context",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, id int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
}, nil
},
},
},
args: args{
role: "admin",
},
wants: wants{
err: true,
},
},
} }
for _, tt := range tests { for _, tt := range tests {
@ -355,10 +85,6 @@ func TestStore_SourcesGet(t *testing.T) {
ctx = context.WithValue(ctx, organizations.ContextKey, tt.args.organization) ctx = context.WithValue(ctx, organizations.ContextKey, tt.args.organization)
} }
if tt.args.role != "" {
ctx = context.WithValue(ctx, roles.ContextKey, tt.args.role)
}
source, err := store.Sources(ctx).Get(ctx, tt.args.id) source, err := store.Sources(ctx).Get(ctx, tt.args.id)
if (err != nil) != tt.wants.err { if (err != nil) != tt.wants.err {
t.Errorf("%q. Store.Sources().Get() error = %v, wantErr %v", tt.name, err, tt.wants.err) t.Errorf("%q. Store.Sources().Get() error = %v, wantErr %v", tt.name, err, tt.wants.err)
@ -377,7 +103,6 @@ func TestStore_SourcesAll(t *testing.T) {
} }
type args struct { type args struct {
organization string organization string
role string
} }
type wants struct { type wants struct {
sources []chronograf.Source sources []chronograf.Source
@ -391,7 +116,7 @@ func TestStore_SourcesAll(t *testing.T) {
wants wants wants wants
}{ }{
{ {
name: "Get viewer sources as viewer", name: "Get sources",
fields: fields{ fields: fields{
SourcesStore: &mocks.SourcesStore{ SourcesStore: &mocks.SourcesStore{
AllF: func(ctx context.Context) ([]chronograf.Source, error) { AllF: func(ctx context.Context) ([]chronograf.Source, error) {
@ -400,7 +125,6 @@ func TestStore_SourcesAll(t *testing.T) {
ID: 1, ID: 1,
Name: "my sweet name", Name: "my sweet name",
Organization: "0", Organization: "0",
Role: "viewer",
}, },
}, nil }, nil
}, },
@ -408,7 +132,6 @@ func TestStore_SourcesAll(t *testing.T) {
}, },
args: args{ args: args{
organization: "0", organization: "0",
role: "viewer",
}, },
wants: wants{ wants: wants{
sources: []chronograf.Source{ sources: []chronograf.Source{
@ -416,13 +139,12 @@ func TestStore_SourcesAll(t *testing.T) {
ID: 1, ID: 1,
Name: "my sweet name", Name: "my sweet name",
Organization: "0", Organization: "0",
Role: "viewer",
}, },
}, },
}, },
}, },
{ {
name: "Get viewer sources as viewer - multiple orgs and multiple roles", name: "Get sources - multiple orgs",
fields: fields{ fields: fields{
SourcesStore: &mocks.SourcesStore{ SourcesStore: &mocks.SourcesStore{
AllF: func(ctx context.Context) ([]chronograf.Source, error) { AllF: func(ctx context.Context) ([]chronograf.Source, error) {
@ -431,31 +153,26 @@ func TestStore_SourcesAll(t *testing.T) {
ID: 1, ID: 1,
Name: "my sweet name", Name: "my sweet name",
Organization: "0", Organization: "0",
Role: "viewer",
}, },
{ {
ID: 2, ID: 2,
Name: "A bad source", Name: "A bad source",
Organization: "0", Organization: "0",
Role: "editor",
}, },
{ {
ID: 3, ID: 3,
Name: "A good source", Name: "A good source",
Organization: "0", Organization: "0",
Role: "admin",
}, },
{ {
ID: 4, ID: 4,
Name: "a source I can has", Name: "a source I can has",
Organization: "0", Organization: "0",
Role: "viewer",
}, },
{ {
ID: 5, ID: 5,
Name: "i'm in the wrong org", Name: "i'm in the wrong org",
Organization: "1", Organization: "1",
Role: "viewer",
}, },
}, nil }, nil
}, },
@ -463,7 +180,6 @@ func TestStore_SourcesAll(t *testing.T) {
}, },
args: args{ args: args{
organization: "0", organization: "0",
role: "viewer",
}, },
wants: wants{ wants: wants{
sources: []chronograf.Source{ sources: []chronograf.Source{
@ -471,165 +187,21 @@ func TestStore_SourcesAll(t *testing.T) {
ID: 1, ID: 1,
Name: "my sweet name", Name: "my sweet name",
Organization: "0", Organization: "0",
Role: "viewer",
},
{
ID: 4,
Name: "a source I can has",
Organization: "0",
Role: "viewer",
},
},
},
},
{
name: "Get editor sources as editor - multiple orgs and multiple roles",
fields: fields{
SourcesStore: &mocks.SourcesStore{
AllF: func(ctx context.Context) ([]chronograf.Source, error) {
return []chronograf.Source{
{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
},
{
ID: 2,
Name: "A bad source",
Organization: "0",
Role: "editor",
},
{
ID: 3,
Name: "A good source",
Organization: "0",
Role: "admin",
},
{
ID: 4,
Name: "a source I can has",
Organization: "0",
Role: "viewer",
},
{
ID: 5,
Name: "i'm in the wrong org",
Organization: "1",
Role: "viewer",
},
{
ID: 2,
Name: "i'm an editor, but wrong org",
Organization: "3",
Role: "editor",
},
}, nil
},
},
},
args: args{
organization: "0",
role: "editor",
},
wants: wants{
sources: []chronograf.Source{
{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
}, },
{ {
ID: 2, ID: 2,
Name: "A bad source", Name: "A bad source",
Organization: "0", Organization: "0",
Role: "editor",
},
{
ID: 4,
Name: "a source I can has",
Organization: "0",
Role: "viewer",
},
},
},
},
{
name: "Get admin sources as admin - multiple orgs and multiple roles",
fields: fields{
SourcesStore: &mocks.SourcesStore{
AllF: func(ctx context.Context) ([]chronograf.Source, error) {
return []chronograf.Source{
{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
},
{
ID: 2,
Name: "A bad source",
Organization: "0",
Role: "editor",
},
{
ID: 3,
Name: "A good source",
Organization: "0",
Role: "admin",
},
{
ID: 4,
Name: "a source I can has",
Organization: "0",
Role: "viewer",
},
{
ID: 5,
Name: "i'm in the wrong org",
Organization: "1",
Role: "viewer",
},
{
ID: 2,
Name: "i'm an editor, but wrong org",
Organization: "3",
Role: "editor",
},
}, nil
},
},
},
args: args{
organization: "0",
role: "admin",
},
wants: wants{
sources: []chronograf.Source{
{
ID: 1,
Name: "my sweet name",
Organization: "0",
Role: "viewer",
},
{
ID: 2,
Name: "A bad source",
Organization: "0",
Role: "editor",
}, },
{ {
ID: 3, ID: 3,
Name: "A good source", Name: "A good source",
Organization: "0", Organization: "0",
Role: "admin",
}, },
{ {
ID: 4, ID: 4,
Name: "a source I can has", Name: "a source I can has",
Organization: "0", Organization: "0",
Role: "viewer",
}, },
}, },
}, },
@ -648,10 +220,6 @@ func TestStore_SourcesAll(t *testing.T) {
ctx = context.WithValue(ctx, organizations.ContextKey, tt.args.organization) ctx = context.WithValue(ctx, organizations.ContextKey, tt.args.organization)
} }
if tt.args.role != "" {
ctx = context.WithValue(ctx, roles.ContextKey, tt.args.role)
}
sources, err := store.Sources(ctx).All(ctx) sources, err := store.Sources(ctx).All(ctx)
if (err != nil) != tt.wants.err { if (err != nil) != tt.wants.err {
t.Errorf("%q. Store.Sources().Get() error = %v, wantErr %v", tt.name, err, tt.wants.err) t.Errorf("%q. Store.Sources().Get() error = %v, wantErr %v", tt.name, err, tt.wants.err)