Merge pull request #13702 from grafana/data-source-instance-to-react
Support Data source permissions
This commit is contained in:
+3
-3
@@ -234,13 +234,13 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
datasourceRoute.Get("/", Wrap(GetDataSources))
|
||||
datasourceRoute.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), Wrap(AddDataSource))
|
||||
datasourceRoute.Put("/:id", bind(m.UpdateDataSourceCommand{}), Wrap(UpdateDataSource))
|
||||
datasourceRoute.Delete("/:id", Wrap(DeleteDataSourceByID))
|
||||
datasourceRoute.Delete("/:id", Wrap(DeleteDataSourceById))
|
||||
datasourceRoute.Delete("/name/:name", Wrap(DeleteDataSourceByName))
|
||||
datasourceRoute.Get("/:id", Wrap(GetDataSourceByID))
|
||||
datasourceRoute.Get("/:id", Wrap(GetDataSourceById))
|
||||
datasourceRoute.Get("/name/:name", Wrap(GetDataSourceByName))
|
||||
}, reqOrgAdmin)
|
||||
|
||||
apiRoute.Get("/datasources/id/:name", Wrap(GetDataSourceIDByName), reqSignedIn)
|
||||
apiRoute.Get("/datasources/id/:name", Wrap(GetDataSourceIdByName), reqSignedIn)
|
||||
|
||||
apiRoute.Get("/plugins", Wrap(GetPluginList))
|
||||
apiRoute.Get("/plugins/:pluginId/settings", Wrap(GetPluginSettingByID))
|
||||
|
||||
+18
-1
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/pluginproxy"
|
||||
@@ -14,6 +15,20 @@ import (
|
||||
const HeaderNameNoBackendCache = "X-Grafana-NoCache"
|
||||
|
||||
func (hs *HTTPServer) getDatasourceFromCache(id int64, c *m.ReqContext) (*m.DataSource, error) {
|
||||
userPermissionsQuery := m.GetDataSourcePermissionsForUserQuery{
|
||||
User: c.SignedInUser,
|
||||
}
|
||||
if err := bus.Dispatch(&userPermissionsQuery); err != nil {
|
||||
if err != bus.ErrHandlerNotFound {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
permissionType, exists := userPermissionsQuery.Result[id]
|
||||
if exists && permissionType != m.DsPermissionQuery {
|
||||
return nil, errors.New("User not allowed to access datasource")
|
||||
}
|
||||
}
|
||||
|
||||
nocache := c.Req.Header.Get(HeaderNameNoBackendCache) == "true"
|
||||
cacheKey := fmt.Sprintf("ds-%d", id)
|
||||
|
||||
@@ -38,7 +53,9 @@ func (hs *HTTPServer) getDatasourceFromCache(id int64, c *m.ReqContext) (*m.Data
|
||||
func (hs *HTTPServer) ProxyDataSourceRequest(c *m.ReqContext) {
|
||||
c.TimeRequest(metrics.M_DataSource_ProxyReq_Timer)
|
||||
|
||||
ds, err := hs.getDatasourceFromCache(c.ParamsInt64(":id"), c)
|
||||
dsId := c.ParamsInt64(":id")
|
||||
ds, err := hs.getDatasourceFromCache(dsId, c)
|
||||
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to load datasource meta data", err)
|
||||
return
|
||||
|
||||
@@ -20,8 +20,8 @@ func GetDataSources(c *m.ReqContext) Response {
|
||||
result := make(dtos.DataSourceList, 0)
|
||||
for _, ds := range query.Result {
|
||||
dsItem := dtos.DataSourceListItemDTO{
|
||||
Id: ds.Id,
|
||||
OrgId: ds.OrgId,
|
||||
Id: ds.Id,
|
||||
Name: ds.Name,
|
||||
Url: ds.Url,
|
||||
Type: ds.Type,
|
||||
@@ -49,7 +49,7 @@ func GetDataSources(c *m.ReqContext) Response {
|
||||
return JSON(200, &result)
|
||||
}
|
||||
|
||||
func GetDataSourceByID(c *m.ReqContext) Response {
|
||||
func GetDataSourceById(c *m.ReqContext) Response {
|
||||
query := m.GetDataSourceByIdQuery{
|
||||
Id: c.ParamsInt64(":id"),
|
||||
OrgId: c.OrgId,
|
||||
@@ -68,14 +68,14 @@ func GetDataSourceByID(c *m.ReqContext) Response {
|
||||
return JSON(200, &dtos)
|
||||
}
|
||||
|
||||
func DeleteDataSourceByID(c *m.ReqContext) Response {
|
||||
func DeleteDataSourceById(c *m.ReqContext) Response {
|
||||
id := c.ParamsInt64(":id")
|
||||
|
||||
if id <= 0 {
|
||||
return Error(400, "Missing valid datasource id", nil)
|
||||
}
|
||||
|
||||
ds, err := getRawDataSourceByID(id, c.OrgId)
|
||||
ds, err := getRawDataSourceById(id, c.OrgId)
|
||||
if err != nil {
|
||||
return Error(400, "Failed to delete datasource", nil)
|
||||
}
|
||||
@@ -186,7 +186,7 @@ func fillWithSecureJSONData(cmd *m.UpdateDataSourceCommand) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
ds, err := getRawDataSourceByID(cmd.Id, cmd.OrgId)
|
||||
ds, err := getRawDataSourceById(cmd.Id, cmd.OrgId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -206,7 +206,7 @@ func fillWithSecureJSONData(cmd *m.UpdateDataSourceCommand) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRawDataSourceByID(id int64, orgID int64) (*m.DataSource, error) {
|
||||
func getRawDataSourceById(id int64, orgID int64) (*m.DataSource, error) {
|
||||
query := m.GetDataSourceByIdQuery{
|
||||
Id: id,
|
||||
OrgId: orgID,
|
||||
@@ -236,7 +236,7 @@ func GetDataSourceByName(c *m.ReqContext) Response {
|
||||
}
|
||||
|
||||
// Get /api/datasources/id/:name
|
||||
func GetDataSourceIDByName(c *m.ReqContext) Response {
|
||||
func GetDataSourceIdByName(c *m.ReqContext) Response {
|
||||
query := m.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId}
|
||||
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
|
||||
@@ -22,7 +22,20 @@ func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orgDataSources = query.Result
|
||||
dsFilterQuery := m.DatasourcesPermissionFilterQuery{
|
||||
User: c.SignedInUser,
|
||||
Datasources: query.Result,
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&dsFilterQuery); err != nil {
|
||||
if err != bus.ErrHandlerNotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orgDataSources = query.Result
|
||||
} else {
|
||||
orgDataSources = dsFilterQuery.Result
|
||||
}
|
||||
}
|
||||
|
||||
datasources := make(map[string]interface{})
|
||||
|
||||
@@ -30,6 +30,7 @@ var (
|
||||
ErrDataSourceNameExists = errors.New("Data source with same name already exists")
|
||||
ErrDataSourceUpdatingOldVersion = errors.New("Trying to update old version of datasource")
|
||||
ErrDatasourceIsReadOnly = errors.New("Data source is readonly. Can only be updated from configuration.")
|
||||
ErrDataSourceAccessDenied = errors.New("Data source access denied")
|
||||
)
|
||||
|
||||
type DsAccess string
|
||||
@@ -167,6 +168,7 @@ type DeleteDataSourceByNameCommand struct {
|
||||
|
||||
type GetDataSourcesQuery struct {
|
||||
OrgId int64
|
||||
User *SignedInUser
|
||||
Result []*DataSource
|
||||
}
|
||||
|
||||
@@ -187,6 +189,31 @@ type GetDataSourceByNameQuery struct {
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// EVENTS
|
||||
type DataSourceCreatedEvent struct {
|
||||
// Permissions
|
||||
// ---------------------
|
||||
|
||||
type DsPermissionType int
|
||||
|
||||
const (
|
||||
DsPermissionNoAccess DsPermissionType = iota
|
||||
DsPermissionQuery
|
||||
)
|
||||
|
||||
func (p DsPermissionType) String() string {
|
||||
names := map[int]string{
|
||||
int(DsPermissionQuery): "Query",
|
||||
int(DsPermissionNoAccess): "No Access",
|
||||
}
|
||||
return names[int(p)]
|
||||
}
|
||||
|
||||
type GetDataSourcePermissionsForUserQuery struct {
|
||||
User *SignedInUser
|
||||
Result map[int64]DsPermissionType
|
||||
}
|
||||
|
||||
type DatasourcesPermissionFilterQuery struct {
|
||||
User *SignedInUser
|
||||
Datasources []*DataSource
|
||||
Result []*DataSource
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ func GetDataSourceById(query *m.GetDataSourceByIdQuery) error {
|
||||
|
||||
datasource := m.DataSource{OrgId: query.OrgId, Id: query.Id}
|
||||
has, err := x.Get(&datasource)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ type SqlStore struct {
|
||||
dbCfg DatabaseConfig
|
||||
engine *xorm.Engine
|
||||
log log.Logger
|
||||
Dialect migrator.Dialect
|
||||
skipEnsureAdmin bool
|
||||
}
|
||||
|
||||
@@ -125,10 +126,12 @@ func (ss *SqlStore) Init() error {
|
||||
}
|
||||
|
||||
ss.engine = engine
|
||||
ss.Dialect = migrator.NewDialect(ss.engine)
|
||||
|
||||
// temporarily still set global var
|
||||
x = engine
|
||||
dialect = migrator.NewDialect(x)
|
||||
dialect = ss.Dialect
|
||||
|
||||
migrator := migrator.NewMigrator(x)
|
||||
migrations.AddMigrations(migrator)
|
||||
|
||||
@@ -347,7 +350,11 @@ func InitTestDB(t *testing.T) *SqlStore {
|
||||
t.Fatalf("Failed to init test database: %v", err)
|
||||
}
|
||||
|
||||
dialect = migrator.NewDialect(engine)
|
||||
sqlstore.Dialect = migrator.NewDialect(engine)
|
||||
|
||||
// temp global var until we get rid of global vars
|
||||
dialect = sqlstore.Dialect
|
||||
|
||||
if err := dialect.CleanDB(); err != nil {
|
||||
t.Fatalf("Failed to clean test db %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user