mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
API: Add by UID routes for data sources (#29884)
- also add Get by UID+OrgID to datasource cache - Refactor backend commands for Delete and Get to be unified
This commit is contained in:
parent
d5cbb17666
commit
1c1a800bc0
@ -31,6 +31,7 @@ Content-Type: application/json
|
|||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"orgId": 1,
|
"orgId": 1,
|
||||||
|
"uid": "H8joYFVGz"
|
||||||
"name": "datasource_elastic",
|
"name": "datasource_elastic",
|
||||||
"type": "elasticsearch",
|
"type": "elasticsearch",
|
||||||
"typeLogoUrl": "public/app/plugins/datasource/elasticsearch/img/elasticsearch.svg",
|
"typeLogoUrl": "public/app/plugins/datasource/elasticsearch/img/elasticsearch.svg",
|
||||||
@ -74,6 +75,53 @@ Content-Type: application/json
|
|||||||
|
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
"uid": "kLtEtcRGk",
|
||||||
|
"orgId": 1,
|
||||||
|
"name": "test_datasource",
|
||||||
|
"type": "graphite",
|
||||||
|
"typeLogoUrl": "",
|
||||||
|
"access": "proxy",
|
||||||
|
"url": "http://mydatasource.com",
|
||||||
|
"password": "",
|
||||||
|
"user": "",
|
||||||
|
"database": "",
|
||||||
|
"basicAuth": false,
|
||||||
|
"basicAuthUser": "",
|
||||||
|
"basicAuthPassword": "",
|
||||||
|
"withCredentials": false,
|
||||||
|
"isDefault": false,
|
||||||
|
"jsonData": {
|
||||||
|
"graphiteType": "default",
|
||||||
|
"graphiteVersion": "1.1"
|
||||||
|
},
|
||||||
|
"secureJsonFields": {},
|
||||||
|
"version": 1,
|
||||||
|
"readOnly": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get a single data source by UID
|
||||||
|
|
||||||
|
`GET /api/datasources/uid/:uid`
|
||||||
|
|
||||||
|
**Example request:**
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/datasources/uid/kLtEtcRGk HTTP/1.1
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Response**:
|
||||||
|
|
||||||
|
```http
|
||||||
|
HTTP/1.1 200
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"uid": "kLtEtcRGk",
|
||||||
"orgId": 1,
|
"orgId": 1,
|
||||||
"name": "test_datasource",
|
"name": "test_datasource",
|
||||||
"type": "graphite",
|
"type": "graphite",
|
||||||
@ -119,6 +167,7 @@ Content-Type: application/json
|
|||||||
|
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
"uid": "kLtEtcRGk",
|
||||||
"orgId": 1,
|
"orgId": 1,
|
||||||
"name": "test_datasource",
|
"name": "test_datasource",
|
||||||
"type": "graphite",
|
"type": "graphite",
|
||||||
@ -396,6 +445,28 @@ Content-Type: application/json
|
|||||||
{"message":"Data source deleted"}
|
{"message":"Data source deleted"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Delete an existing data source by UID
|
||||||
|
|
||||||
|
`DELETE /api/datasources/uid/:uid`
|
||||||
|
|
||||||
|
**Example request:**
|
||||||
|
|
||||||
|
```http
|
||||||
|
DELETE /api/datasources/uid/kLtEtcRGk HTTP/1.1
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example response**:
|
||||||
|
|
||||||
|
```http
|
||||||
|
HTTP/1.1 200
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"message":"Data source deleted"}
|
||||||
|
```
|
||||||
|
|
||||||
## Delete an existing data source by name
|
## Delete an existing data source by name
|
||||||
|
|
||||||
`DELETE /api/datasources/name/:datasourceName`
|
`DELETE /api/datasources/name/:datasourceName`
|
||||||
|
@ -253,8 +253,10 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
datasourceRoute.Post("/", quota("data_source"), bind(models.AddDataSourceCommand{}), Wrap(AddDataSource))
|
datasourceRoute.Post("/", quota("data_source"), bind(models.AddDataSourceCommand{}), Wrap(AddDataSource))
|
||||||
datasourceRoute.Put("/:id", bind(models.UpdateDataSourceCommand{}), Wrap(UpdateDataSource))
|
datasourceRoute.Put("/:id", bind(models.UpdateDataSourceCommand{}), Wrap(UpdateDataSource))
|
||||||
datasourceRoute.Delete("/:id", Wrap(DeleteDataSourceById))
|
datasourceRoute.Delete("/:id", Wrap(DeleteDataSourceById))
|
||||||
|
datasourceRoute.Delete("/uid/:uid", Wrap(DeleteDataSourceByUID))
|
||||||
datasourceRoute.Delete("/name/:name", Wrap(DeleteDataSourceByName))
|
datasourceRoute.Delete("/name/:name", Wrap(DeleteDataSourceByName))
|
||||||
datasourceRoute.Get("/:id", Wrap(GetDataSourceById))
|
datasourceRoute.Get("/:id", Wrap(GetDataSourceById))
|
||||||
|
datasourceRoute.Get("/uid/:uid", Wrap(GetDataSourceByUID))
|
||||||
datasourceRoute.Get("/name/:name", Wrap(GetDataSourceByName))
|
datasourceRoute.Get("/name/:name", Wrap(GetDataSourceByName))
|
||||||
}, reqOrgAdmin)
|
}, reqOrgAdmin)
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ func (hs *HTTPServer) GetDataSources(c *models.ReqContext) Response {
|
|||||||
dsItem := dtos.DataSourceListItemDTO{
|
dsItem := dtos.DataSourceListItemDTO{
|
||||||
OrgId: ds.OrgId,
|
OrgId: ds.OrgId,
|
||||||
Id: ds.Id,
|
Id: ds.Id,
|
||||||
|
UID: ds.Uid,
|
||||||
Name: ds.Name,
|
Name: ds.Name,
|
||||||
Url: ds.Url,
|
Url: ds.Url,
|
||||||
Type: ds.Type,
|
Type: ds.Type,
|
||||||
@ -59,7 +60,7 @@ func (hs *HTTPServer) GetDataSources(c *models.ReqContext) Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetDataSourceById(c *models.ReqContext) Response {
|
func GetDataSourceById(c *models.ReqContext) Response {
|
||||||
query := models.GetDataSourceByIdQuery{
|
query := models.GetDataSourceQuery{
|
||||||
Id: c.ParamsInt64(":id"),
|
Id: c.ParamsInt64(":id"),
|
||||||
OrgId: c.OrgId,
|
OrgId: c.OrgId,
|
||||||
}
|
}
|
||||||
@ -86,6 +87,9 @@ func DeleteDataSourceById(c *models.ReqContext) Response {
|
|||||||
|
|
||||||
ds, err := getRawDataSourceById(id, c.OrgId)
|
ds, err := getRawDataSourceById(id, c.OrgId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, models.ErrDataSourceNotFound) {
|
||||||
|
return Error(404, "Data source not found", nil)
|
||||||
|
}
|
||||||
return Error(400, "Failed to delete datasource", nil)
|
return Error(400, "Failed to delete datasource", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +97,52 @@ func DeleteDataSourceById(c *models.ReqContext) Response {
|
|||||||
return Error(403, "Cannot delete read-only data source", nil)
|
return Error(403, "Cannot delete read-only data source", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &models.DeleteDataSourceByIdCommand{Id: id, OrgId: c.OrgId}
|
cmd := &models.DeleteDataSourceCommand{ID: id, OrgID: c.OrgId}
|
||||||
|
|
||||||
|
err = bus.Dispatch(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return Error(500, "Failed to delete datasource", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Success("Data source deleted")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/datasources/uid/:uid
|
||||||
|
func GetDataSourceByUID(c *models.ReqContext) Response {
|
||||||
|
ds, err := getRawDataSourceByUID(c.Params(":uid"), c.OrgId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, models.ErrDataSourceNotFound) {
|
||||||
|
return Error(404, "Data source not found", nil)
|
||||||
|
}
|
||||||
|
return Error(500, "Failed to query datasources", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dtos := convertModelToDtos(ds)
|
||||||
|
return JSON(200, &dtos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE /api/datasources/uid/:uid
|
||||||
|
func DeleteDataSourceByUID(c *models.ReqContext) Response {
|
||||||
|
uid := c.Params(":uid")
|
||||||
|
|
||||||
|
if uid == "" {
|
||||||
|
return Error(400, "Missing datasource uid", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
ds, err := getRawDataSourceByUID(uid, c.OrgId)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, models.ErrDataSourceNotFound) {
|
||||||
|
return Error(404, "Data source not found", nil)
|
||||||
|
}
|
||||||
|
return Error(400, "Failed to delete datasource", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ds.ReadOnly {
|
||||||
|
return Error(403, "Cannot delete read-only data source", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := &models.DeleteDataSourceCommand{UID: uid, OrgID: c.OrgId}
|
||||||
|
|
||||||
err = bus.Dispatch(cmd)
|
err = bus.Dispatch(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -110,7 +159,7 @@ func DeleteDataSourceByName(c *models.ReqContext) Response {
|
|||||||
return Error(400, "Missing valid datasource name", nil)
|
return Error(400, "Missing valid datasource name", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
getCmd := &models.GetDataSourceByNameQuery{Name: name, OrgId: c.OrgId}
|
getCmd := &models.GetDataSourceQuery{Name: name, OrgId: c.OrgId}
|
||||||
if err := bus.Dispatch(getCmd); err != nil {
|
if err := bus.Dispatch(getCmd); err != nil {
|
||||||
if errors.Is(err, models.ErrDataSourceNotFound) {
|
if errors.Is(err, models.ErrDataSourceNotFound) {
|
||||||
return Error(404, "Data source not found", nil)
|
return Error(404, "Data source not found", nil)
|
||||||
@ -122,7 +171,7 @@ func DeleteDataSourceByName(c *models.ReqContext) Response {
|
|||||||
return Error(403, "Cannot delete read-only data source", nil)
|
return Error(403, "Cannot delete read-only data source", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &models.DeleteDataSourceByNameCommand{Name: name, OrgId: c.OrgId}
|
cmd := &models.DeleteDataSourceCommand{Name: name, OrgID: c.OrgId}
|
||||||
err := bus.Dispatch(cmd)
|
err := bus.Dispatch(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Error(500, "Failed to delete datasource", err)
|
return Error(500, "Failed to delete datasource", err)
|
||||||
@ -191,7 +240,7 @@ func UpdateDataSource(c *models.ReqContext, cmd models.UpdateDataSourceCommand)
|
|||||||
return Error(500, "Failed to update datasource", err)
|
return Error(500, "Failed to update datasource", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
query := models.GetDataSourceByIdQuery{
|
query := models.GetDataSourceQuery{
|
||||||
Id: cmd.Id,
|
Id: cmd.Id,
|
||||||
OrgId: c.OrgId,
|
OrgId: c.OrgId,
|
||||||
}
|
}
|
||||||
@ -238,7 +287,7 @@ func fillWithSecureJSONData(cmd *models.UpdateDataSourceCommand) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getRawDataSourceById(id int64, orgID int64) (*models.DataSource, error) {
|
func getRawDataSourceById(id int64, orgID int64) (*models.DataSource, error) {
|
||||||
query := models.GetDataSourceByIdQuery{
|
query := models.GetDataSourceQuery{
|
||||||
Id: id,
|
Id: id,
|
||||||
OrgId: orgID,
|
OrgId: orgID,
|
||||||
}
|
}
|
||||||
@ -250,9 +299,22 @@ func getRawDataSourceById(id int64, orgID int64) (*models.DataSource, error) {
|
|||||||
return query.Result, nil
|
return query.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRawDataSourceByUID(uid string, orgID int64) (*models.DataSource, error) {
|
||||||
|
query := models.GetDataSourceQuery{
|
||||||
|
Uid: uid,
|
||||||
|
OrgId: orgID,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Get /api/datasources/name/:name
|
// Get /api/datasources/name/:name
|
||||||
func GetDataSourceByName(c *models.ReqContext) Response {
|
func GetDataSourceByName(c *models.ReqContext) Response {
|
||||||
query := models.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId}
|
query := models.GetDataSourceQuery{Name: c.Params(":name"), OrgId: c.OrgId}
|
||||||
|
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
if errors.Is(err, models.ErrDataSourceNotFound) {
|
if errors.Is(err, models.ErrDataSourceNotFound) {
|
||||||
@ -267,7 +329,7 @@ func GetDataSourceByName(c *models.ReqContext) Response {
|
|||||||
|
|
||||||
// Get /api/datasources/id/:name
|
// Get /api/datasources/id/:name
|
||||||
func GetDataSourceIdByName(c *models.ReqContext) Response {
|
func GetDataSourceIdByName(c *models.ReqContext) Response {
|
||||||
query := models.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId}
|
query := models.GetDataSourceQuery{Name: c.Params(":name"), OrgId: c.OrgId}
|
||||||
|
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
if errors.Is(err, models.ErrDataSourceNotFound) {
|
if errors.Is(err, models.ErrDataSourceNotFound) {
|
||||||
@ -321,6 +383,7 @@ func (hs *HTTPServer) CallDatasourceResource(c *models.ReqContext) {
|
|||||||
func convertModelToDtos(ds *models.DataSource) dtos.DataSource {
|
func convertModelToDtos(ds *models.DataSource) dtos.DataSource {
|
||||||
dto := dtos.DataSource{
|
dto := dtos.DataSource{
|
||||||
Id: ds.Id,
|
Id: ds.Id,
|
||||||
|
UID: ds.Uid,
|
||||||
OrgId: ds.OrgId,
|
OrgId: ds.OrgId,
|
||||||
Name: ds.Name,
|
Name: ds.Name,
|
||||||
Url: ds.Url,
|
Url: ds.Url,
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
type DataSource struct {
|
type DataSource struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
|
UID string `json:"uid"`
|
||||||
OrgId int64 `json:"orgId"`
|
OrgId int64 `json:"orgId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
@ -31,6 +32,7 @@ type DataSource struct {
|
|||||||
|
|
||||||
type DataSourceListItemDTO struct {
|
type DataSourceListItemDTO struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
|
UID string `json:"uid"`
|
||||||
OrgId int64 `json:"orgId"`
|
OrgId int64 `json:"orgId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
@ -106,7 +106,7 @@ func registerEndPoint(df ...*data.Frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tsdb.RegisterTsdbQueryEndpoint("test", endpoint)
|
tsdb.RegisterTsdbQueryEndpoint("test", endpoint)
|
||||||
bus.AddHandler("test", func(query *models.GetDataSourceByIdQuery) error {
|
bus.AddHandler("test", func(query *models.GetDataSourceQuery) error {
|
||||||
query.Result = &models.DataSource{Id: 1, OrgId: 1, Type: "test"}
|
query.Result = &models.DataSource{Id: 1, OrgId: 1, Type: "test"}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -136,7 +136,7 @@ func QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.Que
|
|||||||
datasourceID = req.PluginContext.DataSourceInstanceSettings.ID
|
datasourceID = req.PluginContext.DataSourceInstanceSettings.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
getDsInfo := &models.GetDataSourceByIdQuery{
|
getDsInfo := &models.GetDataSourceQuery{
|
||||||
OrgId: req.PluginContext.OrgID,
|
OrgId: req.PluginContext.OrgID,
|
||||||
Id: datasourceID,
|
Id: datasourceID,
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ var (
|
|||||||
ErrDatasourceIsReadOnly = errors.New("data source is readonly, can only be updated from configuration")
|
ErrDatasourceIsReadOnly = errors.New("data source is readonly, can only be updated from configuration")
|
||||||
ErrDataSourceAccessDenied = errors.New("data source access denied")
|
ErrDataSourceAccessDenied = errors.New("data source access denied")
|
||||||
ErrDataSourceFailedGenerateUniqueUid = errors.New("failed to generate unique datasource ID")
|
ErrDataSourceFailedGenerateUniqueUid = errors.New("failed to generate unique datasource ID")
|
||||||
|
ErrDataSourceIdentifierNotSet = errors.New("unique identifier and org id are needed to be able to get or delete a datasource")
|
||||||
)
|
)
|
||||||
|
|
||||||
type DsAccess string
|
type DsAccess string
|
||||||
@ -184,16 +185,14 @@ type UpdateDataSourceCommand struct {
|
|||||||
Result *DataSource
|
Result *DataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteDataSourceByIdCommand struct {
|
// DeleteDataSourceCommand will delete a DataSource based on OrgID as well as the UID (preferred), ID, or Name.
|
||||||
Id int64
|
// At least one of the UID, ID, or Name properties must be set in addition to OrgID.
|
||||||
OrgId int64
|
type DeleteDataSourceCommand struct {
|
||||||
|
ID int64
|
||||||
|
UID string
|
||||||
|
Name string
|
||||||
|
|
||||||
DeletedDatasourcesCount int64
|
OrgID int64
|
||||||
}
|
|
||||||
|
|
||||||
type DeleteDataSourceByNameCommand struct {
|
|
||||||
Name string
|
|
||||||
OrgId int64
|
|
||||||
|
|
||||||
DeletedDatasourcesCount int64
|
DeletedDatasourcesCount int64
|
||||||
}
|
}
|
||||||
@ -214,15 +213,15 @@ type GetDefaultDataSourceQuery struct {
|
|||||||
Result *DataSource
|
Result *DataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetDataSourceByIdQuery struct {
|
// GetDataSourceQuery will get a DataSource based on OrgID as well as the UID (preferred), ID, or Name.
|
||||||
Id int64
|
// At least one of the UID, ID, or Name properties must be set in addition to OrgID.
|
||||||
OrgId int64
|
type GetDataSourceQuery struct {
|
||||||
Result *DataSource
|
Id int64
|
||||||
}
|
Uid string
|
||||||
|
Name string
|
||||||
|
|
||||||
|
OrgId int64
|
||||||
|
|
||||||
type GetDataSourceByNameQuery struct {
|
|
||||||
Name string
|
|
||||||
OrgId int64
|
|
||||||
Result *DataSource
|
Result *DataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func (e *AlertEngine) mapRulesToUsageStats(rules []*models.Alert) (DatasourceAle
|
|||||||
// map of datsource types and frequency
|
// map of datsource types and frequency
|
||||||
result := map[string]int{}
|
result := map[string]int{}
|
||||||
for k, v := range typeCount {
|
for k, v := range typeCount {
|
||||||
query := &models.GetDataSourceByIdQuery{Id: k}
|
query := &models.GetDataSourceQuery{Id: k}
|
||||||
err := e.Bus.Dispatch(query)
|
err := e.Bus.Dispatch(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return map[string]int{}, nil
|
return map[string]int{}, nil
|
||||||
|
@ -38,7 +38,7 @@ func TestAlertingUsageStats(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
ae.Bus.AddHandler(func(query *models.GetDataSourceByIdQuery) error {
|
ae.Bus.AddHandler(func(query *models.GetDataSourceQuery) error {
|
||||||
ds := map[int64]*models.DataSource{
|
ds := map[int64]*models.DataSource{
|
||||||
1: {Type: "influxdb"},
|
1: {Type: "influxdb"},
|
||||||
2: {Type: "graphite"},
|
2: {Type: "graphite"},
|
||||||
|
@ -110,7 +110,7 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange *tsdb.TimeRange) (tsdb.TimeSeriesSlice, error) {
|
func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange *tsdb.TimeRange) (tsdb.TimeSeriesSlice, error) {
|
||||||
getDsInfo := &models.GetDataSourceByIdQuery{
|
getDsInfo := &models.GetDataSourceQuery{
|
||||||
Id: c.Query.DatasourceID,
|
Id: c.Query.DatasourceID,
|
||||||
OrgId: context.Rule.OrgID,
|
OrgId: context.Rule.OrgID,
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ func (ctx *queryConditionTestContext) exec() (*alerting.ConditionResult, error)
|
|||||||
|
|
||||||
func queryConditionScenario(desc string, fn queryConditionScenarioFunc) {
|
func queryConditionScenario(desc string, fn queryConditionScenarioFunc) {
|
||||||
Convey(desc, func() {
|
Convey(desc, func() {
|
||||||
bus.AddHandler("test", func(query *models.GetDataSourceByIdQuery) error {
|
bus.AddHandler("test", func(query *models.GetDataSourceQuery) error {
|
||||||
query.Result = &models.DataSource{Id: 1, Type: "graphite"}
|
query.Result = &models.DataSource{Id: 1, Type: "graphite"}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -39,7 +39,7 @@ func (e *DashAlertExtractor) lookupDatasourceID(dsName string) (*models.DataSour
|
|||||||
return query.Result, nil
|
return query.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
query := &models.GetDataSourceByNameQuery{Name: dsName, OrgId: e.OrgID}
|
query := &models.GetDataSourceQuery{Name: dsName, OrgId: e.OrgID}
|
||||||
if err := bus.Dispatch(query); err != nil {
|
if err := bus.Dispatch(query); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func TestAlertRuleExtraction(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *models.GetDataSourceByNameQuery) error {
|
bus.AddHandler("test", func(query *models.GetDataSourceQuery) error {
|
||||||
if query.Name == defaultDs.Name {
|
if query.Name == defaultDs.Name {
|
||||||
query.Result = defaultDs
|
query.Result = defaultDs
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
type CacheService interface {
|
type CacheService interface {
|
||||||
GetDatasource(datasourceID int64, user *models.SignedInUser, skipCache bool) (*models.DataSource, error)
|
GetDatasource(datasourceID int64, user *models.SignedInUser, skipCache bool) (*models.DataSource, error)
|
||||||
|
GetDatasourceByUID(datasourceUID string, user *models.SignedInUser, skipCache bool) (*models.DataSource, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type CacheServiceImpl struct {
|
type CacheServiceImpl struct {
|
||||||
@ -36,7 +37,7 @@ func (dc *CacheServiceImpl) GetDatasource(
|
|||||||
user *models.SignedInUser,
|
user *models.SignedInUser,
|
||||||
skipCache bool,
|
skipCache bool,
|
||||||
) (*models.DataSource, error) {
|
) (*models.DataSource, error) {
|
||||||
cacheKey := fmt.Sprintf("ds-%d", datasourceID)
|
cacheKey := idKey(datasourceID)
|
||||||
|
|
||||||
if !skipCache {
|
if !skipCache {
|
||||||
if cached, found := dc.CacheService.Get(cacheKey); found {
|
if cached, found := dc.CacheService.Get(cacheKey); found {
|
||||||
@ -48,11 +49,55 @@ func (dc *CacheServiceImpl) GetDatasource(
|
|||||||
}
|
}
|
||||||
|
|
||||||
plog.Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.OrgId)
|
plog.Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.OrgId)
|
||||||
ds, err := dc.SQLStore.GetDataSourceByID(datasourceID, user.OrgId)
|
ds, err := dc.SQLStore.GetDataSource("", datasourceID, "", user.OrgId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ds.Uid != "" {
|
||||||
|
dc.CacheService.Set(uidKey(ds.OrgId, ds.Uid), ds, time.Second*5)
|
||||||
|
}
|
||||||
dc.CacheService.Set(cacheKey, ds, time.Second*5)
|
dc.CacheService.Set(cacheKey, ds, time.Second*5)
|
||||||
return ds, nil
|
return ds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dc *CacheServiceImpl) GetDatasourceByUID(
|
||||||
|
datasourceUID string,
|
||||||
|
user *models.SignedInUser,
|
||||||
|
skipCache bool,
|
||||||
|
) (*models.DataSource, error) {
|
||||||
|
if datasourceUID == "" {
|
||||||
|
return nil, fmt.Errorf("can not get data source by uid, uid is empty")
|
||||||
|
}
|
||||||
|
if user.OrgId == 0 {
|
||||||
|
return nil, fmt.Errorf("can not get data source by uid, orgId is missing")
|
||||||
|
}
|
||||||
|
uidCacheKey := uidKey(user.OrgId, datasourceUID)
|
||||||
|
|
||||||
|
if !skipCache {
|
||||||
|
if cached, found := dc.CacheService.Get(uidCacheKey); found {
|
||||||
|
ds := cached.(*models.DataSource)
|
||||||
|
if ds.OrgId == user.OrgId {
|
||||||
|
return ds, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plog.Debug("Querying for data source via SQL store", "uid", datasourceUID, "orgId", user.OrgId)
|
||||||
|
ds, err := dc.SQLStore.GetDataSource(datasourceUID, 0, "", user.OrgId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dc.CacheService.Set(uidCacheKey, ds, time.Second*5)
|
||||||
|
dc.CacheService.Set(idKey(ds.Id), ds, time.Second*5)
|
||||||
|
return ds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func idKey(id int64) string {
|
||||||
|
return fmt.Sprintf("ds-%d", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func uidKey(orgID int64, uid string) string {
|
||||||
|
return fmt.Sprintf("ds-orgid-uid-%d-%s", orgID, uid)
|
||||||
|
}
|
||||||
|
@ -260,13 +260,13 @@ func validateDatasourceV1(dsCfg *configs) {
|
|||||||
|
|
||||||
type fakeRepository struct {
|
type fakeRepository struct {
|
||||||
inserted []*models.AddDataSourceCommand
|
inserted []*models.AddDataSourceCommand
|
||||||
deleted []*models.DeleteDataSourceByNameCommand
|
deleted []*models.DeleteDataSourceCommand
|
||||||
updated []*models.UpdateDataSourceCommand
|
updated []*models.UpdateDataSourceCommand
|
||||||
|
|
||||||
loadAll []*models.DataSource
|
loadAll []*models.DataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockDelete(cmd *models.DeleteDataSourceByNameCommand) error {
|
func mockDelete(cmd *models.DeleteDataSourceCommand) error {
|
||||||
fakeRepo.deleted = append(fakeRepo.deleted, cmd)
|
fakeRepo.deleted = append(fakeRepo.deleted, cmd)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ func mockInsert(cmd *models.AddDataSourceCommand) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockGet(cmd *models.GetDataSourceByNameQuery) error {
|
func mockGet(cmd *models.GetDataSourceQuery) error {
|
||||||
for _, v := range fakeRepo.loadAll {
|
for _, v := range fakeRepo.loadAll {
|
||||||
if cmd.Name == v.Name && cmd.OrgId == v.OrgId {
|
if cmd.Name == v.Name && cmd.OrgId == v.OrgId {
|
||||||
cmd.Result = v
|
cmd.Result = v
|
||||||
|
@ -43,7 +43,7 @@ func (dc *DatasourceProvisioner) apply(cfg *configs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, ds := range cfg.Datasources {
|
for _, ds := range cfg.Datasources {
|
||||||
cmd := &models.GetDataSourceByNameQuery{OrgId: ds.OrgID, Name: ds.Name}
|
cmd := &models.GetDataSourceQuery{OrgId: ds.OrgID, Name: ds.Name}
|
||||||
err := bus.Dispatch(cmd)
|
err := bus.Dispatch(cmd)
|
||||||
if err != nil && !errors.Is(err, models.ErrDataSourceNotFound) {
|
if err != nil && !errors.Is(err, models.ErrDataSourceNotFound) {
|
||||||
return err
|
return err
|
||||||
@ -84,7 +84,7 @@ func (dc *DatasourceProvisioner) applyChanges(configPath string) error {
|
|||||||
|
|
||||||
func (dc *DatasourceProvisioner) deleteDatasources(dsToDelete []*deleteDatasourceConfig) error {
|
func (dc *DatasourceProvisioner) deleteDatasources(dsToDelete []*deleteDatasourceConfig) error {
|
||||||
for _, ds := range dsToDelete {
|
for _, ds := range dsToDelete {
|
||||||
cmd := &models.DeleteDataSourceByNameCommand{OrgId: ds.OrgID, Name: ds.Name}
|
cmd := &models.DeleteDataSourceCommand{OrgID: ds.OrgID, Name: ds.Name}
|
||||||
if err := bus.Dispatch(cmd); err != nil {
|
if err := bus.Dispatch(cmd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -18,53 +18,50 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
bus.AddHandler("sql", GetDataSources)
|
bus.AddHandler("sql", GetDataSources)
|
||||||
|
bus.AddHandler("sql", GetDataSource)
|
||||||
bus.AddHandler("sql", AddDataSource)
|
bus.AddHandler("sql", AddDataSource)
|
||||||
bus.AddHandler("sql", DeleteDataSourceById)
|
bus.AddHandler("sql", DeleteDataSource)
|
||||||
bus.AddHandler("sql", DeleteDataSourceByName)
|
|
||||||
bus.AddHandler("sql", UpdateDataSource)
|
bus.AddHandler("sql", UpdateDataSource)
|
||||||
bus.AddHandler("sql", GetDataSourceById)
|
|
||||||
bus.AddHandler("sql", GetDataSourceByName)
|
|
||||||
bus.AddHandler("sql", GetDefaultDataSource)
|
bus.AddHandler("sql", GetDefaultDataSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDataSourceByID(id, orgID int64, engine *xorm.Engine) (*models.DataSource, error) {
|
// GetDataSource returns a datasource by org_id and either uid (preferred), id, or name.
|
||||||
metrics.MDBDataSourceQueryByID.Inc()
|
// Zero values (0, or "") should be used for the parameters that will not be queried.
|
||||||
|
func (ss *SQLStore) GetDataSource(uid string, id int64, name string, orgID int64) (*models.DataSource, error) {
|
||||||
|
query := &models.GetDataSourceQuery{
|
||||||
|
Id: id,
|
||||||
|
Uid: uid,
|
||||||
|
Name: name,
|
||||||
|
OrgId: orgID,
|
||||||
|
}
|
||||||
|
|
||||||
datasource := models.DataSource{OrgId: orgID, Id: id}
|
if err := GetDataSource(query); err != nil {
|
||||||
has, err := engine.Get(&datasource)
|
|
||||||
if err != nil {
|
|
||||||
sqlog.Error("Failed getting data source", "err", err, "id", id, "orgId", orgID)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !has {
|
|
||||||
sqlog.Debug("Failed to find data source", "id", id, "orgId", orgID)
|
return query.Result, nil
|
||||||
return nil, models.ErrDataSourceNotFound
|
}
|
||||||
|
|
||||||
|
// GetDataSource adds a datasource to the query model by querying by org_id as well as
|
||||||
|
// either uid (preferred), id, or name and is added to the bus.
|
||||||
|
func GetDataSource(query *models.GetDataSourceQuery) error {
|
||||||
|
metrics.MDBDataSourceQueryByID.Inc()
|
||||||
|
if query.OrgId == 0 || (query.Id == 0 && len(query.Name) == 0 && len(query.Uid) == 0) {
|
||||||
|
return models.ErrDataSourceIdentifierNotSet
|
||||||
}
|
}
|
||||||
|
|
||||||
return &datasource, nil
|
datasource := models.DataSource{Name: query.Name, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *SQLStore) GetDataSourceByID(id, orgID int64) (*models.DataSource, error) {
|
|
||||||
return getDataSourceByID(id, orgID, ss.engine)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDataSourceById(query *models.GetDataSourceByIdQuery) error {
|
|
||||||
ds, err := getDataSourceByID(query.Id, query.OrgId, x)
|
|
||||||
query.Result = ds
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDataSourceByName(query *models.GetDataSourceByNameQuery) error {
|
|
||||||
datasource := models.DataSource{OrgId: query.OrgId, Name: query.Name}
|
|
||||||
has, err := x.Get(&datasource)
|
has, err := x.Get(&datasource)
|
||||||
|
|
||||||
if !has {
|
if err != nil {
|
||||||
|
sqlog.Error("Failed getting data source", "err", err, "uid", query.Uid, "id", query.Id, "name", query.Name, "orgId", query.OrgId)
|
||||||
|
return err
|
||||||
|
} else if !has {
|
||||||
return models.ErrDataSourceNotFound
|
return models.ErrDataSourceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
query.Result = &datasource
|
query.Result = &datasource
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDataSources(query *models.GetDataSourcesQuery) error {
|
func GetDataSources(query *models.GetDataSourcesQuery) error {
|
||||||
@ -92,22 +89,49 @@ func GetDefaultDataSource(query *models.GetDefaultDataSourceQuery) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteDataSourceById(cmd *models.DeleteDataSourceByIdCommand) error {
|
// DeleteDataSource deletes a datasource by org_id and either uid (preferred), id, or name.
|
||||||
return inTransaction(func(sess *DBSession) error {
|
// Zero values (0, or "") should be used for the parameters that will not be queried.
|
||||||
var rawSQL = "DELETE FROM data_source WHERE id=? and org_id=?"
|
func (ss *SQLStore) DeleteDataSource(uid string, id int64, name string, orgID int64) (int64, error) {
|
||||||
result, err := sess.Exec(rawSQL, cmd.Id, cmd.OrgId)
|
cmd := &models.DeleteDataSourceCommand{
|
||||||
affected, _ := result.RowsAffected()
|
ID: id,
|
||||||
cmd.DeletedDatasourcesCount = affected
|
UID: uid,
|
||||||
return err
|
Name: name,
|
||||||
})
|
OrgID: orgID,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := DeleteDataSource(cmd); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd.DeletedDatasourcesCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteDataSourceByName(cmd *models.DeleteDataSourceByNameCommand) error {
|
// DeleteDataSource removes a datasource by org_id as well as either uid (preferred), id, or name
|
||||||
|
// and is added to the bus.
|
||||||
|
func DeleteDataSource(cmd *models.DeleteDataSourceCommand) error {
|
||||||
|
params := make([]interface{}, 0)
|
||||||
|
|
||||||
|
makeQuery := func(sql string, p ...interface{}) {
|
||||||
|
params = append(params, sql)
|
||||||
|
params = append(params, p...)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case cmd.OrgID == 0:
|
||||||
|
return models.ErrDataSourceIdentifierNotSet
|
||||||
|
case cmd.UID != "":
|
||||||
|
makeQuery("DELETE FROM data_source WHERE uid=? and org_id=?", cmd.UID, cmd.OrgID)
|
||||||
|
case cmd.ID != 0:
|
||||||
|
makeQuery("DELETE FROM data_source WHERE id=? and org_id=?", cmd.ID, cmd.OrgID)
|
||||||
|
case cmd.Name != "":
|
||||||
|
makeQuery("DELETE FROM data_source WHERE name=? and org_id=?", cmd.Name, cmd.OrgID)
|
||||||
|
default:
|
||||||
|
return models.ErrDataSourceIdentifierNotSet
|
||||||
|
}
|
||||||
|
|
||||||
return inTransaction(func(sess *DBSession) error {
|
return inTransaction(func(sess *DBSession) error {
|
||||||
var rawSQL = "DELETE FROM data_source WHERE name=? and org_id=?"
|
result, err := sess.Exec(params...)
|
||||||
result, err := sess.Exec(rawSQL, cmd.Name, cmd.OrgId)
|
cmd.DeletedDatasourcesCount, _ = result.RowsAffected()
|
||||||
affected, _ := result.RowsAffected()
|
|
||||||
cmd.DeletedDatasourcesCount = affected
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -110,8 +110,8 @@ func TestDataAccess(t *testing.T) {
|
|||||||
err := UpdateDataSource(&cmd)
|
err := UpdateDataSource(&cmd)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
query := models.GetDataSourceByIdQuery{Id: ds.Id}
|
query := models.GetDataSourceQuery{Id: ds.Id, OrgId: 10}
|
||||||
err = GetDataSourceById(&query)
|
err = GetDataSource(&query)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ds.Uid, query.Result.Uid)
|
require.Equal(t, ds.Uid, query.Result.Uid)
|
||||||
})
|
})
|
||||||
@ -180,7 +180,7 @@ func TestDataAccess(t *testing.T) {
|
|||||||
InitTestDB(t)
|
InitTestDB(t)
|
||||||
ds := initDatasource()
|
ds := initDatasource()
|
||||||
|
|
||||||
err := DeleteDataSourceById(&models.DeleteDataSourceByIdCommand{Id: ds.Id, OrgId: ds.OrgId})
|
err := DeleteDataSource(&models.DeleteDataSourceCommand{ID: ds.Id, OrgID: ds.OrgId})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||||
@ -194,7 +194,7 @@ func TestDataAccess(t *testing.T) {
|
|||||||
InitTestDB(t)
|
InitTestDB(t)
|
||||||
ds := initDatasource()
|
ds := initDatasource()
|
||||||
|
|
||||||
err := DeleteDataSourceById(&models.DeleteDataSourceByIdCommand{Id: ds.Id, OrgId: 123123})
|
err := DeleteDataSource(&models.DeleteDataSourceCommand{ID: ds.Id, OrgID: 123123})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||||
err = GetDataSources(&query)
|
err = GetDataSources(&query)
|
||||||
@ -209,7 +209,7 @@ func TestDataAccess(t *testing.T) {
|
|||||||
ds := initDatasource()
|
ds := initDatasource()
|
||||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||||
|
|
||||||
err := DeleteDataSourceByName(&models.DeleteDataSourceByNameCommand{Name: ds.Name, OrgId: ds.OrgId})
|
err := DeleteDataSource(&models.DeleteDataSourceCommand{Name: ds.Name, OrgID: ds.OrgId})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = GetDataSources(&query)
|
err = GetDataSources(&query)
|
||||||
|
Loading…
Reference in New Issue
Block a user