290 lines
9.4 KiB
Go
290 lines
9.4 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/influxdata/influxdb/v2/chronograf"
|
|
"github.com/influxdata/influxdb/v2/chronograf/noop"
|
|
"github.com/influxdata/influxdb/v2/chronograf/organizations"
|
|
"github.com/influxdata/influxdb/v2/chronograf/roles"
|
|
)
|
|
|
|
// hasOrganizationContext retrieves organization specified on context
|
|
// under the organizations.ContextKey
|
|
func hasOrganizationContext(ctx context.Context) (string, bool) {
|
|
// prevents panic in case of nil context
|
|
if ctx == nil {
|
|
return "", false
|
|
}
|
|
orgID, ok := ctx.Value(organizations.ContextKey).(string)
|
|
// should never happen
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
if orgID == "" {
|
|
return "", false
|
|
}
|
|
return orgID, true
|
|
}
|
|
|
|
// hasRoleContext retrieves organization specified on context
|
|
// under the organizations.ContextKey
|
|
func hasRoleContext(ctx context.Context) (string, bool) {
|
|
// prevents panic in case of nil context
|
|
if ctx == nil {
|
|
return "", false
|
|
}
|
|
role, ok := ctx.Value(roles.ContextKey).(string)
|
|
// should never happen
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
switch role {
|
|
case roles.MemberRoleName, roles.ViewerRoleName, roles.EditorRoleName, roles.AdminRoleName:
|
|
return role, true
|
|
default:
|
|
return "", false
|
|
}
|
|
}
|
|
|
|
type userContextKey string
|
|
|
|
// UserContextKey is the context key for retrieving the user off of context
|
|
const UserContextKey = userContextKey("user")
|
|
|
|
// hasUserContext speficies if the context contains
|
|
// the UserContextKey and that the value stored there is chronograf.User
|
|
func hasUserContext(ctx context.Context) (*chronograf.User, bool) {
|
|
// prevents panic in case of nil context
|
|
if ctx == nil {
|
|
return nil, false
|
|
}
|
|
u, ok := ctx.Value(UserContextKey).(*chronograf.User)
|
|
// should never happen
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
if u == nil {
|
|
return nil, false
|
|
}
|
|
return u, true
|
|
}
|
|
|
|
// hasSuperAdminContext speficies if the context contains
|
|
// the UserContextKey user is a super admin
|
|
func hasSuperAdminContext(ctx context.Context) bool {
|
|
u, ok := hasUserContext(ctx)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return u.SuperAdmin
|
|
}
|
|
|
|
// DataStore is collection of resources that are used by the Service
|
|
// Abstracting this into an interface was useful for isolated testing
|
|
type DataStore interface {
|
|
Sources(ctx context.Context) chronograf.SourcesStore
|
|
Servers(ctx context.Context) chronograf.ServersStore
|
|
Layouts(ctx context.Context) chronograf.LayoutsStore
|
|
Users(ctx context.Context) chronograf.UsersStore
|
|
Organizations(ctx context.Context) chronograf.OrganizationsStore
|
|
Mappings(ctx context.Context) chronograf.MappingsStore
|
|
Dashboards(ctx context.Context) chronograf.DashboardsStore
|
|
Config(ctx context.Context) chronograf.ConfigStore
|
|
OrganizationConfig(ctx context.Context) chronograf.OrganizationConfigStore
|
|
}
|
|
|
|
// ensure that Store implements a DataStore
|
|
var _ DataStore = &Store{}
|
|
|
|
// Store implements the DataStore interface
|
|
type Store struct {
|
|
SourcesStore chronograf.SourcesStore
|
|
ServersStore chronograf.ServersStore
|
|
LayoutsStore chronograf.LayoutsStore
|
|
UsersStore chronograf.UsersStore
|
|
DashboardsStore chronograf.DashboardsStore
|
|
MappingsStore chronograf.MappingsStore
|
|
OrganizationsStore chronograf.OrganizationsStore
|
|
ConfigStore chronograf.ConfigStore
|
|
OrganizationConfigStore chronograf.OrganizationConfigStore
|
|
}
|
|
|
|
// Sources returns a noop.SourcesStore if the context has no organization specified
|
|
// and an organization.SourcesStore otherwise.
|
|
func (s *Store) Sources(ctx context.Context) chronograf.SourcesStore {
|
|
if isServer := hasServerContext(ctx); isServer {
|
|
return s.SourcesStore
|
|
}
|
|
if org, ok := hasOrganizationContext(ctx); ok {
|
|
return organizations.NewSourcesStore(s.SourcesStore, org)
|
|
}
|
|
|
|
return &noop.SourcesStore{}
|
|
}
|
|
|
|
// Servers returns a noop.ServersStore if the context has no organization specified
|
|
// and an organization.ServersStore otherwise.
|
|
func (s *Store) Servers(ctx context.Context) chronograf.ServersStore {
|
|
if isServer := hasServerContext(ctx); isServer {
|
|
return s.ServersStore
|
|
}
|
|
if org, ok := hasOrganizationContext(ctx); ok {
|
|
return organizations.NewServersStore(s.ServersStore, org)
|
|
}
|
|
|
|
return &noop.ServersStore{}
|
|
}
|
|
|
|
// Layouts returns all layouts in the underlying layouts store.
|
|
func (s *Store) Layouts(ctx context.Context) chronograf.LayoutsStore {
|
|
return s.LayoutsStore
|
|
}
|
|
|
|
// Users returns a chronograf.UsersStore.
|
|
// If the context is a server context, then the underlying chronograf.UsersStore
|
|
// is returned.
|
|
// If there is an organization specified on context, then an organizations.UsersStore
|
|
// is returned.
|
|
// If niether are specified, a noop.UsersStore is returned.
|
|
func (s *Store) Users(ctx context.Context) chronograf.UsersStore {
|
|
if isServer := hasServerContext(ctx); isServer {
|
|
return s.UsersStore
|
|
}
|
|
if org, ok := hasOrganizationContext(ctx); ok {
|
|
return organizations.NewUsersStore(s.UsersStore, org)
|
|
}
|
|
|
|
return &noop.UsersStore{}
|
|
}
|
|
|
|
// Dashboards returns a noop.DashboardsStore if the context has no organization specified
|
|
// and an organization.DashboardsStore otherwise.
|
|
func (s *Store) Dashboards(ctx context.Context) chronograf.DashboardsStore {
|
|
if isServer := hasServerContext(ctx); isServer {
|
|
return s.DashboardsStore
|
|
}
|
|
if org, ok := hasOrganizationContext(ctx); ok {
|
|
return organizations.NewDashboardsStore(s.DashboardsStore, org)
|
|
}
|
|
|
|
return &noop.DashboardsStore{}
|
|
}
|
|
|
|
// OrganizationConfig returns a noop.OrganizationConfigStore if the context has no organization specified
|
|
// and an organization.OrganizationConfigStore otherwise.
|
|
func (s *Store) OrganizationConfig(ctx context.Context) chronograf.OrganizationConfigStore {
|
|
if orgID, ok := hasOrganizationContext(ctx); ok {
|
|
return organizations.NewOrganizationConfigStore(s.OrganizationConfigStore, orgID)
|
|
}
|
|
|
|
return &noop.OrganizationConfigStore{}
|
|
}
|
|
|
|
// Organizations returns the underlying OrganizationsStore.
|
|
func (s *Store) Organizations(ctx context.Context) chronograf.OrganizationsStore {
|
|
if isServer := hasServerContext(ctx); isServer {
|
|
return s.OrganizationsStore
|
|
}
|
|
if isSuperAdmin := hasSuperAdminContext(ctx); isSuperAdmin {
|
|
return s.OrganizationsStore
|
|
}
|
|
if org, ok := hasOrganizationContext(ctx); ok {
|
|
return organizations.NewOrganizationsStore(s.OrganizationsStore, org)
|
|
}
|
|
return &noop.OrganizationsStore{}
|
|
}
|
|
|
|
// Config returns the underlying ConfigStore.
|
|
func (s *Store) Config(ctx context.Context) chronograf.ConfigStore {
|
|
if isServer := hasServerContext(ctx); isServer {
|
|
return s.ConfigStore
|
|
}
|
|
if isSuperAdmin := hasSuperAdminContext(ctx); isSuperAdmin {
|
|
return s.ConfigStore
|
|
}
|
|
|
|
return &noop.ConfigStore{}
|
|
}
|
|
|
|
// Mappings returns the underlying MappingsStore.
|
|
func (s *Store) Mappings(ctx context.Context) chronograf.MappingsStore {
|
|
if isServer := hasServerContext(ctx); isServer {
|
|
return s.MappingsStore
|
|
}
|
|
if isSuperAdmin := hasSuperAdminContext(ctx); isSuperAdmin {
|
|
return s.MappingsStore
|
|
}
|
|
return &noop.MappingsStore{}
|
|
}
|
|
|
|
// ensure that DirectStore implements a DataStore
|
|
var _ DataStore = &DirectStore{}
|
|
|
|
// Store implements the DataStore interface
|
|
type DirectStore struct {
|
|
SourcesStore chronograf.SourcesStore
|
|
ServersStore chronograf.ServersStore
|
|
LayoutsStore chronograf.LayoutsStore
|
|
UsersStore chronograf.UsersStore
|
|
DashboardsStore chronograf.DashboardsStore
|
|
MappingsStore chronograf.MappingsStore
|
|
OrganizationsStore chronograf.OrganizationsStore
|
|
ConfigStore chronograf.ConfigStore
|
|
OrganizationConfigStore chronograf.OrganizationConfigStore
|
|
}
|
|
|
|
// Sources returns a noop.SourcesStore if the context has no organization specified
|
|
// and an organization.SourcesStore otherwise.
|
|
func (s *DirectStore) Sources(ctx context.Context) chronograf.SourcesStore {
|
|
return s.SourcesStore
|
|
}
|
|
|
|
// Servers returns a noop.ServersStore if the context has no organization specified
|
|
// and an organization.ServersStore otherwise.
|
|
func (s *DirectStore) Servers(ctx context.Context) chronograf.ServersStore {
|
|
return s.ServersStore
|
|
}
|
|
|
|
// Layouts returns all layouts in the underlying layouts store.
|
|
func (s *DirectStore) Layouts(ctx context.Context) chronograf.LayoutsStore {
|
|
return s.LayoutsStore
|
|
}
|
|
|
|
// Users returns a chronograf.UsersStore.
|
|
// If the context is a server context, then the underlying chronograf.UsersStore
|
|
// is returned.
|
|
// If there is an organization specified on context, then an organizations.UsersStore
|
|
// is returned.
|
|
// If niether are specified, a noop.UsersStore is returned.
|
|
func (s *DirectStore) Users(ctx context.Context) chronograf.UsersStore {
|
|
return s.UsersStore
|
|
}
|
|
|
|
// Dashboards returns a noop.DashboardsStore if the context has no organization specified
|
|
// and an organization.DashboardsStore otherwise.
|
|
func (s *DirectStore) Dashboards(ctx context.Context) chronograf.DashboardsStore {
|
|
return s.DashboardsStore
|
|
}
|
|
|
|
// OrganizationConfig returns a noop.OrganizationConfigStore if the context has no organization specified
|
|
// and an organization.OrganizationConfigStore otherwise.
|
|
func (s *DirectStore) OrganizationConfig(ctx context.Context) chronograf.OrganizationConfigStore {
|
|
return s.OrganizationConfigStore
|
|
}
|
|
|
|
// Organizations returns the underlying OrganizationsStore.
|
|
func (s *DirectStore) Organizations(ctx context.Context) chronograf.OrganizationsStore {
|
|
return s.OrganizationsStore
|
|
}
|
|
|
|
// Config returns the underlying ConfigStore.
|
|
func (s *DirectStore) Config(ctx context.Context) chronograf.ConfigStore {
|
|
return s.ConfigStore
|
|
}
|
|
|
|
// Mappings returns the underlying MappingsStore.
|
|
func (s *DirectStore) Mappings(ctx context.Context) chronograf.MappingsStore {
|
|
return s.MappingsStore
|
|
}
|