2014-12-29 06:36:08 -06:00
package api
import (
2021-10-07 09:33:50 -05:00
"context"
2020-03-18 06:08:52 -05:00
"encoding/json"
2020-11-19 06:34:28 -06:00
"errors"
2020-04-22 03:30:06 -05:00
"fmt"
2021-11-29 03:18:01 -06:00
"net/http"
2016-03-15 14:29:35 -05:00
"sort"
2022-01-14 10:55:57 -06:00
"strconv"
2022-09-20 12:31:08 -05:00
"strings"
2016-03-15 14:29:35 -05:00
2021-10-07 09:33:50 -05:00
"github.com/grafana/grafana-plugin-sdk-go/backend"
2022-06-27 11:23:15 -05:00
2020-05-12 06:04:18 -05:00
"github.com/grafana/grafana/pkg/api/datasource"
2015-02-05 03:37:13 -06:00
"github.com/grafana/grafana/pkg/api/dtos"
2021-01-15 07:43:20 -06:00
"github.com/grafana/grafana/pkg/api/response"
2022-09-20 12:31:08 -05:00
"github.com/grafana/grafana/pkg/components/simplejson"
2020-06-17 04:17:11 -05:00
"github.com/grafana/grafana/pkg/infra/log"
2020-03-04 05:57:20 -06:00
"github.com/grafana/grafana/pkg/models"
2021-03-08 00:02:49 -06:00
"github.com/grafana/grafana/pkg/plugins/adapters"
2022-03-24 06:21:26 -05:00
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/datasources/permissions"
2022-08-10 04:56:48 -05:00
"github.com/grafana/grafana/pkg/services/user"
2022-09-20 12:31:08 -05:00
"github.com/grafana/grafana/pkg/setting"
2015-06-01 05:15:49 -05:00
"github.com/grafana/grafana/pkg/util"
2022-05-31 10:58:06 -05:00
"github.com/grafana/grafana/pkg/util/proxyutil"
2021-10-11 07:30:59 -05:00
"github.com/grafana/grafana/pkg/web"
2014-12-29 06:36:08 -06:00
)
2020-06-17 04:17:11 -05:00
var datasourcesLogger = log . New ( "datasources" )
2022-06-27 11:23:15 -05:00
var secretsPluginError datasources . ErrDatasourceSecretsPluginUserFriendly
2020-06-17 04:17:11 -05:00
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources datasources getDataSources
//
// Get all data sources.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:read` and scope: `datasources:*`.
//
// Responses:
// 200: getDataSourcesResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2021-01-15 07:43:20 -06:00
func ( hs * HTTPServer ) GetDataSources ( c * models . ReqContext ) response . Response {
2022-08-11 06:28:55 -05:00
query := datasources . GetDataSourcesQuery { OrgId : c . OrgID , DataSourceLimit : hs . Cfg . DataSourceLimit }
2014-12-29 06:36:08 -06:00
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . GetDataSources ( c . Req . Context ( ) , & query ) ; err != nil {
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to query datasources" , err )
2014-12-29 06:36:08 -06:00
}
2022-02-09 07:01:32 -06:00
filtered , err := hs . filterDatasourcesByQueryPermission ( c . Req . Context ( ) , c . SignedInUser , query . Result )
2022-01-17 03:16:12 -06:00
if err != nil {
return response . Error ( 500 , "Failed to query datasources" , err )
}
2016-03-15 14:29:35 -05:00
result := make ( dtos . DataSourceList , 0 )
2022-01-17 03:16:12 -06:00
for _ , ds := range filtered {
2017-04-25 08:17:49 -05:00
dsItem := dtos . DataSourceListItemDTO {
2015-02-23 13:07:49 -06:00
OrgId : ds . OrgId ,
2018-10-01 08:38:55 -05:00
Id : ds . Id ,
2021-01-13 12:16:27 -06:00
UID : ds . Uid ,
2014-12-29 06:36:08 -06:00
Name : ds . Name ,
Url : ds . Url ,
Type : ds . Type ,
2021-02-22 06:02:10 -06:00
TypeName : ds . Type ,
2014-12-29 06:36:08 -06:00
Access : ds . Access ,
Database : ds . Database ,
User : ds . User ,
BasicAuth : ds . BasicAuth ,
2015-01-09 09:36:23 -06:00
IsDefault : ds . IsDefault ,
2016-09-01 10:21:13 -05:00
JsonData : ds . JsonData ,
2017-10-24 08:28:39 -05:00
ReadOnly : ds . ReadOnly ,
2014-12-29 06:36:08 -06:00
}
2016-03-15 14:29:35 -05:00
2021-11-17 05:04:22 -06:00
if plugin , exists := hs . pluginStore . Plugin ( c . Req . Context ( ) , ds . Type ) ; exists {
2016-03-15 14:29:35 -05:00
dsItem . TypeLogoUrl = plugin . Info . Logos . Small
2021-02-22 06:02:10 -06:00
dsItem . TypeName = plugin . Name
2016-03-15 14:29:35 -05:00
} else {
2016-03-23 09:09:48 -05:00
dsItem . TypeLogoUrl = "public/img/icn-datasource.svg"
2016-03-15 14:29:35 -05:00
}
result = append ( result , dsItem )
2014-12-29 06:36:08 -06:00
}
2016-03-15 14:29:35 -05:00
sort . Sort ( result )
2017-02-08 07:20:07 -06:00
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , & result )
2014-12-29 06:36:08 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources/{id} datasources getDataSourceByID
//
// Get a single data source by Id.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:read` and scopes: `datasources:*`, `datasources:id:*` and `datasources:id:1` (single data source).
//
// Please refer to [updated API](#/datasources/getDataSourceByUID) instead
//
// Deprecated: true
//
// Responses:
// 200: getDataSourceResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2021-12-15 05:08:15 -06:00
func ( hs * HTTPServer ) GetDataSourceById ( c * models . ReqContext ) response . Response {
2022-01-14 10:55:57 -06:00
id , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":id" ] , 10 , 64 )
if err != nil {
2022-09-05 08:10:45 -05:00
return response . Error ( http . StatusBadRequest , "id is invalid" , nil )
2022-01-14 10:55:57 -06:00
}
2022-06-27 11:23:15 -05:00
query := datasources . GetDataSourceQuery {
2022-01-14 10:55:57 -06:00
Id : id ,
2022-08-11 06:28:55 -05:00
OrgId : c . OrgID ,
2015-02-14 03:04:27 -06:00
}
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . GetDataSource ( c . Req . Context ( ) , & query ) ; err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 404 , "Data source not found" , nil )
2015-11-13 02:43:25 -06:00
}
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceIdentifierNotSet ) {
2021-03-29 01:56:58 -05:00
return response . Error ( 400 , "Datasource id is missing" , nil )
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to query datasources" , err )
2015-02-14 03:04:27 -06:00
}
2022-06-09 06:56:24 -05:00
dto := hs . convertModelToDtos ( c . Req . Context ( ) , query . Result )
2022-02-18 04:27:00 -06:00
2021-12-15 05:08:15 -06:00
// Add accesscontrol metadata
2022-08-11 06:28:55 -05:00
dto . AccessControl = hs . getAccessControlMetadata ( c , c . OrgID , datasources . ScopePrefix , dto . UID )
2021-12-15 05:08:15 -06:00
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , & dto )
2015-02-14 03:04:27 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route DELETE /datasources/{id} datasources deleteDataSourceByID
//
// Delete an existing data source by id.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:delete` and scopes: `datasources:*`, `datasources:id:*` and `datasources:id:1` (single data source).
//
// Please refer to [updated API](#/datasources/deleteDataSourceByUID) instead
//
// Deprecated: true
//
// Responses:
// 200: okResponse
// 401: unauthorisedError
// 404: notFoundError
// 403: forbiddenError
// 500: internalServerError
2021-05-18 13:39:56 -05:00
func ( hs * HTTPServer ) DeleteDataSourceById ( c * models . ReqContext ) response . Response {
2022-01-14 10:55:57 -06:00
id , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":id" ] , 10 , 64 )
if err != nil {
return response . Error ( http . StatusBadRequest , "id is invalid" , err )
}
2014-12-29 06:36:08 -06:00
if id <= 0 {
2021-01-15 07:43:20 -06:00
return response . Error ( 400 , "Missing valid datasource id" , nil )
2014-12-29 06:36:08 -06:00
}
2022-08-11 06:28:55 -05:00
ds , err := hs . getRawDataSourceById ( c . Req . Context ( ) , id , c . OrgID )
2017-10-24 08:28:39 -05:00
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 404 , "Data source not found" , nil )
2021-01-13 12:16:27 -06:00
}
2021-01-15 07:43:20 -06:00
return response . Error ( 400 , "Failed to delete datasource" , nil )
2021-01-13 12:16:27 -06:00
}
if ds . ReadOnly {
2021-01-15 07:43:20 -06:00
return response . Error ( 403 , "Cannot delete read-only data source" , nil )
2021-01-13 12:16:27 -06:00
}
2022-08-11 06:28:55 -05:00
cmd := & datasources . DeleteDataSourceCommand { ID : id , OrgID : c . OrgID , Name : ds . Name }
2021-01-13 12:16:27 -06:00
2022-02-11 08:52:14 -06:00
err = hs . DataSourcesService . DeleteDataSource ( c . Req . Context ( ) , cmd )
2021-01-13 12:16:27 -06:00
if err != nil {
2022-06-16 11:26:57 -05:00
if errors . As ( err , & secretsPluginError ) {
return response . Error ( 500 , "Failed to delete datasource: " + err . Error ( ) , err )
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to delete datasource" , err )
2021-01-13 12:16:27 -06:00
}
2022-08-11 06:28:55 -05:00
hs . Live . HandleDatasourceDelete ( c . OrgID , ds . Uid )
2021-05-18 13:39:56 -05:00
2021-01-15 07:43:20 -06:00
return response . Success ( "Data source deleted" )
2021-01-13 12:16:27 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources/uid/{uid} datasources getDataSourceByUID
//
// Get a single data source by UID.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:read` and scopes: `datasources:*`, `datasources:uid:*` and `datasources:uid:kLtEtcRGk` (single data source).
//
// Responses:
// 200: getDataSourceResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2021-12-15 05:08:15 -06:00
func ( hs * HTTPServer ) GetDataSourceByUID ( c * models . ReqContext ) response . Response {
2022-08-11 06:28:55 -05:00
ds , err := hs . getRawDataSourceByUID ( c . Req . Context ( ) , web . Params ( c . Req ) [ ":uid" ] , c . OrgID )
2021-01-13 12:16:27 -06:00
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2021-12-15 05:08:15 -06:00
return response . Error ( http . StatusNotFound , "Data source not found" , nil )
2021-01-13 12:16:27 -06:00
}
2021-12-15 05:08:15 -06:00
return response . Error ( http . StatusInternalServerError , "Failed to query datasource" , err )
2021-01-13 12:16:27 -06:00
}
2022-06-09 06:56:24 -05:00
dto := hs . convertModelToDtos ( c . Req . Context ( ) , ds )
2021-12-15 05:08:15 -06:00
// Add accesscontrol metadata
2022-08-11 06:28:55 -05:00
dto . AccessControl = hs . getAccessControlMetadata ( c , c . OrgID , datasources . ScopePrefix , dto . UID )
2022-03-24 02:58:10 -05:00
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , & dto )
2021-01-13 12:16:27 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route DELETE /datasources/uid/{uid} datasources deleteDataSourceByUID
//
// Delete an existing data source by UID.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:delete` and scopes: `datasources:*`, `datasources:uid:*` and `datasources:uid:kLtEtcRGk` (single data source).
//
// Responses:
// 200: okResponse
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2021-05-18 13:39:56 -05:00
func ( hs * HTTPServer ) DeleteDataSourceByUID ( c * models . ReqContext ) response . Response {
2021-10-11 07:30:59 -05:00
uid := web . Params ( c . Req ) [ ":uid" ]
2021-01-13 12:16:27 -06:00
if uid == "" {
2021-01-15 07:43:20 -06:00
return response . Error ( 400 , "Missing datasource uid" , nil )
2021-01-13 12:16:27 -06:00
}
2022-08-11 06:28:55 -05:00
ds , err := hs . getRawDataSourceByUID ( c . Req . Context ( ) , uid , c . OrgID )
2021-01-13 12:16:27 -06:00
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 404 , "Data source not found" , nil )
2021-01-13 12:16:27 -06:00
}
2021-01-15 07:43:20 -06:00
return response . Error ( 400 , "Failed to delete datasource" , nil )
2017-10-24 08:28:39 -05:00
}
if ds . ReadOnly {
2021-01-15 07:43:20 -06:00
return response . Error ( 403 , "Cannot delete read-only data source" , nil )
2017-10-24 08:28:39 -05:00
}
2022-08-11 06:28:55 -05:00
cmd := & datasources . DeleteDataSourceCommand { UID : uid , OrgID : c . OrgID , Name : ds . Name }
2017-02-09 20:11:36 -06:00
2022-02-11 08:52:14 -06:00
err = hs . DataSourcesService . DeleteDataSource ( c . Req . Context ( ) , cmd )
2017-02-09 20:11:36 -06:00
if err != nil {
2022-06-16 11:26:57 -05:00
if errors . As ( err , & secretsPluginError ) {
return response . Error ( 500 , "Failed to delete datasource: " + err . Error ( ) , err )
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to delete datasource" , err )
2017-02-09 20:11:36 -06:00
}
2022-08-11 06:28:55 -05:00
hs . Live . HandleDatasourceDelete ( c . OrgID , ds . Uid )
2021-05-18 13:39:56 -05:00
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , util . DynMap {
2021-11-05 09:06:14 -05:00
"message" : "Data source deleted" ,
"id" : ds . Id ,
} )
2017-02-09 20:11:36 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route DELETE /datasources/name/{name} datasources deleteDataSourceByName
//
// Delete an existing data source by name.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:delete` and scopes: `datasources:*`, `datasources:name:*` and `datasources:name:test_datasource` (single data source).
//
// Responses:
// 200: deleteDataSourceByNameResponse
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2021-05-18 13:39:56 -05:00
func ( hs * HTTPServer ) DeleteDataSourceByName ( c * models . ReqContext ) response . Response {
2021-10-11 07:30:59 -05:00
name := web . Params ( c . Req ) [ ":name" ]
2017-02-09 20:11:36 -06:00
if name == "" {
2021-01-15 07:43:20 -06:00
return response . Error ( 400 , "Missing valid datasource name" , nil )
2017-02-09 20:11:36 -06:00
}
2022-08-11 06:28:55 -05:00
getCmd := & datasources . GetDataSourceQuery { Name : name , OrgId : c . OrgID }
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . GetDataSource ( c . Req . Context ( ) , getCmd ) ; err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 404 , "Data source not found" , nil )
2018-06-22 21:15:36 -05:00
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to delete datasource" , err )
2017-10-24 08:28:39 -05:00
}
if getCmd . Result . ReadOnly {
2021-01-15 07:43:20 -06:00
return response . Error ( 403 , "Cannot delete read-only data source" , nil )
2017-10-24 08:28:39 -05:00
}
2014-12-29 06:36:08 -06:00
2022-08-11 06:28:55 -05:00
cmd := & datasources . DeleteDataSourceCommand { Name : name , OrgID : c . OrgID }
2022-02-11 08:52:14 -06:00
err := hs . DataSourcesService . DeleteDataSource ( c . Req . Context ( ) , cmd )
2014-12-29 06:36:08 -06:00
if err != nil {
2022-06-16 11:26:57 -05:00
if errors . As ( err , & secretsPluginError ) {
return response . Error ( 500 , "Failed to delete datasource: " + err . Error ( ) , err )
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to delete datasource" , err )
2014-12-29 06:36:08 -06:00
}
2022-08-11 06:28:55 -05:00
hs . Live . HandleDatasourceDelete ( c . OrgID , getCmd . Result . Uid )
2021-05-18 13:39:56 -05:00
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , util . DynMap {
2020-07-31 01:22:09 -05:00
"message" : "Data source deleted" ,
"id" : getCmd . Result . Id ,
} )
2014-12-29 06:36:08 -06:00
}
2022-01-31 09:39:55 -06:00
func validateURL ( cmdType string , url string ) response . Response {
if _ , err := datasource . ValidateURL ( cmdType , url ) ; err != nil {
2022-07-29 07:46:51 -05:00
datasourcesLogger . Error ( "Failed to validate URL" , "url" , url )
return response . Error ( http . StatusBadRequest , "Validation error, invalid URL" , err )
2020-04-22 03:30:06 -05:00
}
return nil
}
2022-09-20 12:31:08 -05:00
// validateJSONData prevents the user from adding a custom header with name that matches the auth proxy header name.
// This is done to prevent data source proxy from being used to circumvent auth proxy.
// For more context take a look at CVE-2022-35957
func validateJSONData ( jsonData * simplejson . Json , cfg * setting . Cfg ) error {
if jsonData == nil || ! cfg . AuthProxyEnabled {
return nil
}
for key , value := range jsonData . MustMap ( ) {
if strings . HasPrefix ( key , "httpHeaderName" ) {
header := fmt . Sprint ( value )
if http . CanonicalHeaderKey ( header ) == http . CanonicalHeaderKey ( cfg . AuthProxyHeaderName ) {
datasourcesLogger . Error ( "Forbidden to add a data source header with a name equal to auth proxy header name" , "headerName" , key )
return errors . New ( "validation error, invalid header name specified" )
}
}
}
return nil
}
2022-07-27 08:54:37 -05:00
// swagger:route POST /datasources datasources addDataSource
//
// Create a data source.
//
// By defining `password` and `basicAuthPassword` under secureJsonData property
// Grafana encrypts them securely as an encrypted blob in the database.
// The response then lists the encrypted fields under secureJsonFields.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:create`
//
// Responses:
// 200: createOrUpdateDatasourceResponse
// 401: unauthorisedError
// 403: forbiddenError
// 409: conflictError
// 500: internalServerError
2022-02-09 07:01:32 -06:00
func ( hs * HTTPServer ) AddDataSource ( c * models . ReqContext ) response . Response {
2022-06-27 11:23:15 -05:00
cmd := datasources . AddDataSourceCommand { }
2021-11-29 03:18:01 -06:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
return response . Error ( http . StatusBadRequest , "bad request data" , err )
}
2022-01-31 09:39:55 -06:00
2020-06-17 04:17:11 -05:00
datasourcesLogger . Debug ( "Received command to add data source" , "url" , cmd . Url )
2022-08-11 06:28:55 -05:00
cmd . OrgId = c . OrgID
cmd . UserId = c . UserID
2022-01-31 09:39:55 -06:00
if cmd . Url != "" {
if resp := validateURL ( cmd . Type , cmd . Url ) ; resp != nil {
return resp
}
2020-04-22 03:30:06 -05:00
}
2022-09-20 12:31:08 -05:00
if err := validateJSONData ( cmd . JsonData , hs . Cfg ) ; err != nil {
return response . Error ( http . StatusBadRequest , "Failed to add datasource" , err )
}
2014-12-29 06:36:08 -06:00
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . AddDataSource ( c . Req . Context ( ) , & cmd ) ; err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNameExists ) || errors . Is ( err , datasources . ErrDataSourceUidExists ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 409 , err . Error ( ) , err )
2016-10-01 09:41:27 -05:00
}
2022-06-16 11:26:57 -05:00
if errors . As ( err , & secretsPluginError ) {
return response . Error ( 500 , "Failed to add datasource: " + err . Error ( ) , err )
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to add datasource" , err )
2014-12-29 06:36:08 -06:00
}
2022-04-25 11:57:45 -05:00
ds := hs . convertModelToDtos ( c . Req . Context ( ) , cmd . Result )
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , util . DynMap {
2017-10-19 10:28:54 -05:00
"message" : "Datasource added" ,
"id" : cmd . Result . Id ,
"name" : cmd . Result . Name ,
"datasource" : ds ,
} )
2014-12-29 06:36:08 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route PUT /datasources/{id} datasources updateDataSourceByID
//
// Update an existing data source by its sequential ID.
//
// Similar to creating a data source, `password` and `basicAuthPassword` should be defined under
// secureJsonData in order to be stored securely as an encrypted blob in the database. Then, the
// encrypted fields are listed under secureJsonFields section in the response.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:write` and scopes: `datasources:*`, `datasources:id:*` and `datasources:id:1` (single data source).
//
// Please refer to [updated API](#/datasources/updateDataSourceByUID) instead
//
// Deprecated: true
//
// Responses:
// 200: createOrUpdateDatasourceResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2022-05-23 08:13:13 -05:00
func ( hs * HTTPServer ) UpdateDataSourceByID ( c * models . ReqContext ) response . Response {
2022-06-27 11:23:15 -05:00
cmd := datasources . UpdateDataSourceCommand { }
2021-11-29 03:18:01 -06:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
return response . Error ( http . StatusBadRequest , "bad request data" , err )
}
2020-06-17 04:17:11 -05:00
datasourcesLogger . Debug ( "Received command to update data source" , "url" , cmd . Url )
2022-08-11 06:28:55 -05:00
cmd . OrgId = c . OrgID
2022-01-14 10:55:57 -06:00
var err error
2022-01-31 09:39:55 -06:00
if cmd . Id , err = strconv . ParseInt ( web . Params ( c . Req ) [ ":id" ] , 10 , 64 ) ; err != nil {
2022-01-14 10:55:57 -06:00
return response . Error ( http . StatusBadRequest , "id is invalid" , err )
}
2020-06-17 04:17:11 -05:00
if resp := validateURL ( cmd . Type , cmd . Url ) ; resp != nil {
2020-04-22 03:30:06 -05:00
return resp
}
2022-09-20 12:31:08 -05:00
if err := validateJSONData ( cmd . JsonData , hs . Cfg ) ; err != nil {
return response . Error ( http . StatusBadRequest , "Failed to update datasource" , err )
}
2014-12-29 06:36:08 -06:00
2022-02-09 07:01:32 -06:00
ds , err := hs . getRawDataSourceById ( c . Req . Context ( ) , cmd . Id , cmd . OrgId )
2022-01-21 17:22:43 -06:00
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2022-01-21 17:22:43 -06:00
return response . Error ( 404 , "Data source not found" , nil )
}
return response . Error ( 500 , "Failed to update datasource" , err )
}
2022-05-23 08:13:13 -05:00
return hs . updateDataSourceByID ( c , ds , cmd )
}
2022-07-27 08:54:37 -05:00
// swagger:route PUT /datasources/uid/{uid} datasources updateDataSourceByUID
//
// Update an existing data source.
//
// Similar to creating a data source, `password` and `basicAuthPassword` should be defined under
// secureJsonData in order to be stored securely as an encrypted blob in the database. Then, the
// encrypted fields are listed under secureJsonFields section in the response.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:write` and scopes: `datasources:*`, `datasources:uid:*` and `datasources:uid:1` (single data source).
//
// Responses:
// 200: createOrUpdateDatasourceResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2022-05-23 08:13:13 -05:00
func ( hs * HTTPServer ) UpdateDataSourceByUID ( c * models . ReqContext ) response . Response {
2022-06-27 11:23:15 -05:00
cmd := datasources . UpdateDataSourceCommand { }
2022-05-23 08:13:13 -05:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
return response . Error ( http . StatusBadRequest , "bad request data" , err )
}
datasourcesLogger . Debug ( "Received command to update data source" , "url" , cmd . Url )
2022-08-11 06:28:55 -05:00
cmd . OrgId = c . OrgID
2022-05-23 08:13:13 -05:00
if resp := validateURL ( cmd . Type , cmd . Url ) ; resp != nil {
return resp
}
2022-09-20 12:31:08 -05:00
if err := validateJSONData ( cmd . JsonData , hs . Cfg ) ; err != nil {
return response . Error ( http . StatusBadRequest , "Failed to update datasource" , err )
}
2022-05-23 08:13:13 -05:00
2022-08-11 06:28:55 -05:00
ds , err := hs . getRawDataSourceByUID ( c . Req . Context ( ) , web . Params ( c . Req ) [ ":uid" ] , c . OrgID )
2022-05-23 08:13:13 -05:00
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2022-05-23 08:13:13 -05:00
return response . Error ( http . StatusNotFound , "Data source not found" , nil )
}
return response . Error ( http . StatusInternalServerError , "Failed to update datasource" , err )
}
cmd . Id = ds . Id
return hs . updateDataSourceByID ( c , ds , cmd )
}
2022-01-21 17:22:43 -06:00
2022-06-27 11:23:15 -05:00
func ( hs * HTTPServer ) updateDataSourceByID ( c * models . ReqContext , ds * datasources . DataSource , cmd datasources . UpdateDataSourceCommand ) response . Response {
2022-01-21 17:22:43 -06:00
if ds . ReadOnly {
return response . Error ( 403 , "Cannot update read-only data source" , nil )
}
2022-05-23 08:13:13 -05:00
err := hs . DataSourcesService . UpdateDataSource ( c . Req . Context ( ) , & cmd )
2016-11-18 09:44:59 -06:00
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceUpdatingOldVersion ) {
2021-03-29 09:03:15 -05:00
return response . Error ( 409 , "Datasource has already been updated by someone else. Please reload and try again" , err )
2017-10-19 10:28:54 -05:00
}
2022-06-16 11:26:57 -05:00
if errors . As ( err , & secretsPluginError ) {
return response . Error ( 500 , "Failed to update datasource: " + err . Error ( ) , err )
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to update datasource" , err )
2014-12-29 06:36:08 -06:00
}
2018-08-07 10:56:02 -05:00
2022-06-27 11:23:15 -05:00
query := datasources . GetDataSourceQuery {
2018-08-07 10:56:02 -05:00
Id : cmd . Id ,
2022-08-11 06:28:55 -05:00
OrgId : c . OrgID ,
2018-08-07 10:56:02 -05:00
}
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . GetDataSource ( c . Req . Context ( ) , & query ) ; err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 404 , "Data source not found" , nil )
2018-08-07 10:56:02 -05:00
}
2021-05-18 13:39:56 -05:00
return response . Error ( 500 , "Failed to query datasource" , err )
2018-08-07 10:56:02 -05:00
}
2022-04-25 11:57:45 -05:00
datasourceDTO := hs . convertModelToDtos ( c . Req . Context ( ) , query . Result )
2021-05-18 13:39:56 -05:00
2022-08-11 06:28:55 -05:00
hs . Live . HandleDatasourceUpdate ( c . OrgID , datasourceDTO . UID )
2018-08-07 10:56:02 -05:00
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , util . DynMap {
2017-10-19 10:28:54 -05:00
"message" : "Datasource updated" ,
"id" : cmd . Id ,
"name" : cmd . Name ,
2021-05-18 13:39:56 -05:00
"datasource" : datasourceDTO ,
2017-10-19 10:28:54 -05:00
} )
2016-11-18 09:44:59 -06:00
}
2022-06-27 11:23:15 -05:00
func ( hs * HTTPServer ) getRawDataSourceById ( ctx context . Context , id int64 , orgID int64 ) ( * datasources . DataSource , error ) {
query := datasources . GetDataSourceQuery {
2016-11-18 09:44:59 -06:00
Id : id ,
2018-03-22 06:37:35 -05:00
OrgId : orgID ,
2016-11-18 09:44:59 -06:00
}
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . GetDataSource ( ctx , & query ) ; err != nil {
2016-11-18 09:44:59 -06:00
return nil , err
}
return query . Result , nil
2014-12-29 06:36:08 -06:00
}
2015-02-28 01:25:13 -06:00
2022-06-27 11:23:15 -05:00
func ( hs * HTTPServer ) getRawDataSourceByUID ( ctx context . Context , uid string , orgID int64 ) ( * datasources . DataSource , error ) {
query := datasources . GetDataSourceQuery {
2021-01-13 12:16:27 -06:00
Uid : uid ,
OrgId : orgID ,
}
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . GetDataSource ( ctx , & query ) ; err != nil {
2021-01-13 12:16:27 -06:00
return nil , err
}
return query . Result , nil
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources/name/{name} datasources getDataSourceByName
//
// Get a single data source by Name.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:read` and scopes: `datasources:*`, `datasources:name:*` and `datasources:name:test_datasource` (single data source).
//
// Responses:
// 200: getDataSourceResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2022-02-09 07:01:32 -06:00
func ( hs * HTTPServer ) GetDataSourceByName ( c * models . ReqContext ) response . Response {
2022-08-11 06:28:55 -05:00
query := datasources . GetDataSourceQuery { Name : web . Params ( c . Req ) [ ":name" ] , OrgId : c . OrgID }
2016-03-07 14:25:26 -06:00
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . GetDataSource ( c . Req . Context ( ) , & query ) ; err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 404 , "Data source not found" , nil )
2016-03-07 14:25:26 -06:00
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to query datasources" , err )
2016-03-07 14:25:26 -06:00
}
2022-06-09 06:56:24 -05:00
dto := hs . convertModelToDtos ( c . Req . Context ( ) , query . Result )
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , & dto )
2016-03-08 04:51:03 -06:00
}
2016-03-07 14:25:26 -06:00
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources/id/{name} datasources getDataSourceIdByName
//
// Get data source Id by Name.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `datasources:read` and scopes: `datasources:*`, `datasources:name:*` and `datasources:name:test_datasource` (single data source).
//
// Responses:
// 200: getDataSourceIDResponse
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2022-02-09 07:01:32 -06:00
func ( hs * HTTPServer ) GetDataSourceIdByName ( c * models . ReqContext ) response . Response {
2022-08-11 06:28:55 -05:00
query := datasources . GetDataSourceQuery { Name : web . Params ( c . Req ) [ ":name" ] , OrgId : c . OrgID }
2016-03-10 03:31:10 -06:00
2022-02-11 08:52:14 -06:00
if err := hs . DataSourcesService . GetDataSource ( c . Req . Context ( ) , & query ) ; err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceNotFound ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 404 , "Data source not found" , nil )
2016-03-10 03:31:10 -06:00
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to query datasources" , err )
2016-03-10 03:31:10 -06:00
}
ds := query . Result
dtos := dtos . AnyId {
Id : ds . Id ,
}
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , & dtos )
2016-03-10 03:31:10 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources/{id}/resources/{datasource_proxy_route} datasources callDatasourceResourceByID
//
// Fetch data source resources by Id.
//
// Please refer to [updated API](#/datasources/callDatasourceResourceWithUID) instead
//
// Deprecated: true
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2020-03-04 05:57:20 -06:00
func ( hs * HTTPServer ) CallDatasourceResource ( c * models . ReqContext ) {
2022-01-14 10:55:57 -06:00
datasourceID , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":id" ] , 10 , 64 )
if err != nil {
2022-09-05 08:10:45 -05:00
c . JsonApiErr ( http . StatusBadRequest , "id is invalid" , nil )
2022-01-14 10:55:57 -06:00
return
}
2021-12-22 04:02:42 -06:00
ds , err := hs . DataSourceCache . GetDatasource ( c . Req . Context ( ) , datasourceID , c . SignedInUser , c . SkipCache )
2020-01-31 04:15:50 -06:00
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceAccessDenied ) {
2020-03-03 04:45:16 -06:00
c . JsonApiErr ( 403 , "Access denied to datasource" , err )
return
2020-01-31 04:15:50 -06:00
}
2020-03-03 04:45:16 -06:00
c . JsonApiErr ( 500 , "Unable to load datasource meta data" , err )
return
2020-01-31 04:15:50 -06:00
}
2021-11-17 05:04:22 -06:00
plugin , exists := hs . pluginStore . Plugin ( c . Req . Context ( ) , ds . Type )
if ! exists {
2020-03-03 04:45:16 -06:00
c . JsonApiErr ( 500 , "Unable to find datasource plugin" , err )
return
}
2022-05-06 03:58:02 -05:00
hs . callPluginResourceWithDataSource ( c , plugin . ID , ds )
2020-01-31 04:15:50 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources/uid/{uid}/resources/{datasource_proxy_route} datasources callDatasourceResourceWithUID
//
// Fetch data source resources.
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2022-05-19 11:27:59 -05:00
func ( hs * HTTPServer ) CallDatasourceResourceWithUID ( c * models . ReqContext ) {
dsUID := web . Params ( c . Req ) [ ":uid" ]
if ! util . IsValidShortUID ( dsUID ) {
c . JsonApiErr ( http . StatusBadRequest , "UID is invalid" , nil )
return
}
ds , err := hs . DataSourceCache . GetDatasourceByUID ( c . Req . Context ( ) , dsUID , c . SignedInUser , c . SkipCache )
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceAccessDenied ) {
2022-05-19 11:27:59 -05:00
c . JsonApiErr ( http . StatusForbidden , "Access denied to datasource" , err )
return
}
c . JsonApiErr ( http . StatusInternalServerError , "Unable to load datasource meta data" , err )
return
}
plugin , exists := hs . pluginStore . Plugin ( c . Req . Context ( ) , ds . Type )
if ! exists {
c . JsonApiErr ( http . StatusInternalServerError , "Unable to find datasource plugin" , err )
return
}
hs . callPluginResourceWithDataSource ( c , plugin . ID , ds )
}
2022-06-27 11:23:15 -05:00
func ( hs * HTTPServer ) convertModelToDtos ( ctx context . Context , ds * datasources . DataSource ) dtos . DataSource {
2016-11-18 09:44:59 -06:00
dto := dtos . DataSource {
2022-06-03 10:38:22 -05:00
Id : ds . Id ,
UID : ds . Uid ,
OrgId : ds . OrgId ,
Name : ds . Name ,
Url : ds . Url ,
Type : ds . Type ,
Access : ds . Access ,
Database : ds . Database ,
User : ds . User ,
BasicAuth : ds . BasicAuth ,
BasicAuthUser : ds . BasicAuthUser ,
WithCredentials : ds . WithCredentials ,
IsDefault : ds . IsDefault ,
JsonData : ds . JsonData ,
SecureJsonFields : map [ string ] bool { } ,
Version : ds . Version ,
ReadOnly : ds . ReadOnly ,
2016-11-18 09:44:59 -06:00
}
2022-04-25 11:57:45 -05:00
secrets , err := hs . DataSourcesService . DecryptedValues ( ctx , ds )
if err == nil {
for k , v := range secrets {
if len ( v ) > 0 {
dto . SecureJsonFields [ k ] = true
}
2016-11-24 09:24:47 -06:00
}
2022-04-25 13:12:44 -05:00
} else {
datasourcesLogger . Debug ( "Failed to retrieve datasource secrets to parse secure json fields" , "error" , err )
2016-11-24 09:24:47 -06:00
}
2016-11-18 09:44:59 -06:00
return dto
2016-03-07 14:25:26 -06:00
}
2020-03-13 06:31:44 -05:00
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources/uid/{uid}/health datasources checkDatasourceHealthWithUID
//
// Sends a health check request to the plugin datasource identified by the UID.
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2022-05-19 11:27:59 -05:00
func ( hs * HTTPServer ) CheckDatasourceHealthWithUID ( c * models . ReqContext ) response . Response {
dsUID := web . Params ( c . Req ) [ ":uid" ]
if ! util . IsValidShortUID ( dsUID ) {
return response . Error ( http . StatusBadRequest , "UID is invalid" , nil )
}
ds , err := hs . DataSourceCache . GetDatasourceByUID ( c . Req . Context ( ) , dsUID , c . SignedInUser , c . SkipCache )
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceAccessDenied ) {
2022-05-19 11:27:59 -05:00
return response . Error ( http . StatusForbidden , "Access denied to datasource" , err )
}
return response . Error ( http . StatusInternalServerError , "Unable to load datasource metadata" , err )
}
return hs . checkDatasourceHealth ( c , ds )
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /datasources/{id}/health datasources checkDatasourceHealthByID
//
// Sends a health check request to the plugin datasource identified by the ID.
//
// Please refer to [updated API](#/datasources/checkDatasourceHealthWithUID) instead
//
// Deprecated: true
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2021-01-15 07:43:20 -06:00
func ( hs * HTTPServer ) CheckDatasourceHealth ( c * models . ReqContext ) response . Response {
2022-01-14 10:55:57 -06:00
datasourceID , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":id" ] , 10 , 64 )
if err != nil {
2022-09-05 08:10:45 -05:00
return response . Error ( http . StatusBadRequest , "id is invalid" , nil )
2022-01-14 10:55:57 -06:00
}
2020-03-13 06:31:44 -05:00
2021-12-22 04:02:42 -06:00
ds , err := hs . DataSourceCache . GetDatasource ( c . Req . Context ( ) , datasourceID , c . SignedInUser , c . SkipCache )
2020-03-13 06:31:44 -05:00
if err != nil {
2022-06-27 11:23:15 -05:00
if errors . Is ( err , datasources . ErrDataSourceAccessDenied ) {
2022-01-27 11:06:38 -06:00
return response . Error ( http . StatusForbidden , "Access denied to datasource" , err )
2020-03-13 06:31:44 -05:00
}
2022-01-27 11:06:38 -06:00
return response . Error ( http . StatusInternalServerError , "Unable to load datasource metadata" , err )
2020-03-13 06:31:44 -05:00
}
2022-05-19 11:27:59 -05:00
return hs . checkDatasourceHealth ( c , ds )
}
2020-03-13 06:31:44 -05:00
2022-06-27 11:23:15 -05:00
func ( hs * HTTPServer ) checkDatasourceHealth ( c * models . ReqContext , ds * datasources . DataSource ) response . Response {
2021-11-17 05:04:22 -06:00
plugin , exists := hs . pluginStore . Plugin ( c . Req . Context ( ) , ds . Type )
if ! exists {
2022-05-19 11:27:59 -05:00
return response . Error ( http . StatusInternalServerError , "Unable to find datasource plugin" , nil )
2020-03-13 06:31:44 -05:00
}
2022-04-25 11:57:45 -05:00
dsInstanceSettings , err := adapters . ModelToInstanceSettings ( ds , hs . decryptSecureJsonDataFn ( c . Req . Context ( ) ) )
2020-04-23 13:08:21 -05:00
if err != nil {
2022-01-27 11:06:38 -06:00
return response . Error ( http . StatusInternalServerError , "Unable to get datasource model" , err )
2020-04-23 13:08:21 -05:00
}
2021-11-01 04:53:33 -05:00
req := & backend . CheckHealthRequest {
PluginContext : backend . PluginContext {
User : adapters . BackendUserFromSignedInUser ( c . SignedInUser ) ,
2022-08-11 06:28:55 -05:00
OrgID : c . OrgID ,
2021-11-01 04:53:33 -05:00
PluginID : plugin . ID ,
DataSourceInstanceSettings : dsInstanceSettings ,
} ,
2022-05-31 10:58:06 -05:00
Headers : map [ string ] string { } ,
2020-04-23 13:08:21 -05:00
}
2022-01-27 11:06:38 -06:00
var dsURL string
if req . PluginContext . DataSourceInstanceSettings != nil {
dsURL = req . PluginContext . DataSourceInstanceSettings . URL
}
err = hs . PluginRequestValidator . Validate ( dsURL , c . Req )
if err != nil {
return response . Error ( http . StatusForbidden , "Access denied" , err )
}
2022-05-31 10:58:06 -05:00
if hs . DataProxy . OAuthTokenService . IsOAuthPassThruEnabled ( ds ) {
if token := hs . DataProxy . OAuthTokenService . GetCurrentOAuthToken ( c . Req . Context ( ) , c . SignedInUser ) ; token != nil {
req . Headers [ "Authorization" ] = fmt . Sprintf ( "%s %s" , token . Type ( ) , token . AccessToken )
idToken , ok := token . Extra ( "id_token" ) . ( string )
if ok && idToken != "" {
req . Headers [ "X-ID-Token" ] = idToken
}
}
}
2022-10-21 06:54:55 -05:00
proxyutil . ClearCookieHeader ( c . Req , ds . AllowedCookies ( ) , [ ] string { hs . Cfg . LoginCookieName } )
2022-05-31 10:58:06 -05:00
if cookieStr := c . Req . Header . Get ( "Cookie" ) ; cookieStr != "" {
req . Headers [ "Cookie" ] = cookieStr
}
2021-11-01 04:53:33 -05:00
resp , err := hs . pluginClient . CheckHealth ( c . Req . Context ( ) , req )
2020-03-13 06:31:44 -05:00
if err != nil {
2020-06-11 09:14:05 -05:00
return translatePluginRequestErrorToAPIError ( err )
2020-03-13 06:31:44 -05:00
}
payload := map [ string ] interface { } {
2020-03-18 06:08:52 -05:00
"status" : resp . Status . String ( ) ,
"message" : resp . Message ,
}
// Unmarshal JSONDetails if it's not empty.
if len ( resp . JSONDetails ) > 0 {
2020-04-21 09:16:41 -05:00
var jsonDetails map [ string ] interface { }
2020-03-18 06:08:52 -05:00
err = json . Unmarshal ( resp . JSONDetails , & jsonDetails )
if err != nil {
2022-01-27 11:06:38 -06:00
return response . Error ( http . StatusInternalServerError , "Failed to unmarshal detailed response from backend plugin" , err )
2020-03-18 06:08:52 -05:00
}
payload [ "details" ] = jsonDetails
2020-03-13 06:31:44 -05:00
}
2020-06-11 09:14:05 -05:00
if resp . Status != backend . HealthStatusOk {
2022-01-27 11:06:38 -06:00
return response . JSON ( http . StatusBadRequest , payload )
2020-03-13 06:31:44 -05:00
}
2022-01-27 11:06:38 -06:00
return response . JSON ( http . StatusOK , payload )
2020-03-13 06:31:44 -05:00
}
2021-10-07 09:33:50 -05:00
2022-07-13 08:27:03 -05:00
func ( hs * HTTPServer ) decryptSecureJsonDataFn ( ctx context . Context ) func ( ds * datasources . DataSource ) ( map [ string ] string , error ) {
return func ( ds * datasources . DataSource ) ( map [ string ] string , error ) {
return hs . DataSourcesService . DecryptedValues ( ctx , ds )
2021-10-07 09:33:50 -05:00
}
}
2022-01-17 03:16:12 -06:00
2022-08-10 04:56:48 -05:00
func ( hs * HTTPServer ) filterDatasourcesByQueryPermission ( ctx context . Context , user * user . SignedInUser , ds [ ] * datasources . DataSource ) ( [ ] * datasources . DataSource , error ) {
2022-06-27 11:23:15 -05:00
query := datasources . DatasourcesPermissionFilterQuery {
2022-01-17 03:16:12 -06:00
User : user ,
2022-06-27 11:23:15 -05:00
Datasources : ds ,
2022-01-17 03:16:12 -06:00
}
2022-06-27 11:23:15 -05:00
query . Result = ds
2022-01-17 03:16:12 -06:00
2022-02-09 07:01:32 -06:00
if err := hs . DatasourcePermissionsService . FilterDatasourcesBasedOnQueryPermissions ( ctx , & query ) ; err != nil {
2022-03-02 04:04:29 -06:00
if ! errors . Is ( err , permissions . ErrNotImplemented ) {
2022-01-17 03:16:12 -06:00
return nil , err
}
2022-06-27 11:23:15 -05:00
return ds , nil
2022-01-17 03:16:12 -06:00
}
2022-02-01 08:00:05 -06:00
return query . Result , nil
2022-01-17 03:16:12 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:parameters checkDatasourceHealthByID
type CheckDatasourceHealthByIDParams struct {
// in:path
// required:true
DatasourceID string ` json:"id" `
}
// swagger:parameters callDatasourceResourceByID
type CallDatasourceResourceByIDParams struct {
// in:path
// required:true
DatasourceID string ` json:"id" `
}
// swagger:parameters deleteDataSourceByID
type DeleteDataSourceByIDParams struct {
// in:path
// required:true
DatasourceID string ` json:"id" `
}
// swagger:parameters getDataSourceByID
type GetDataSourceByIDParams struct {
// in:path
// required:true
DatasourceID string ` json:"id" `
}
// swagger:parameters checkDatasourceHealthWithUID
type CheckDatasourceHealthWithUIDParams struct {
// in:path
// required:true
DatasourceUID string ` json:"uid" `
}
// swagger:parameters callDatasourceResourceWithUID
type CallDatasourceResourceWithUIDParams struct {
// in:path
// required:true
DatasourceUID string ` json:"uid" `
}
// swagger:parameters deleteDataSourceByUID
type DeleteDataSourceByUIDParams struct {
// in:path
// required:true
DatasourceUID string ` json:"uid" `
}
// swagger:parameters getDataSourceByUID
type GetDataSourceByUIDParams struct {
// in:path
// required:true
DatasourceUID string ` json:"uid" `
}
// swagger:parameters getDataSourceByName
type GetDataSourceByNameParams struct {
// in:path
// required:true
DatasourceName string ` json:"name" `
}
// swagger:parameters deleteDataSourceByName
type DeleteDataSourceByNameParams struct {
// in:path
// required:true
DatasourceName string ` json:"name" `
}
// swagger:parameters getDataSourceIdByName
type GetDataSourceIdByNameParams struct {
// in:path
// required:true
DatasourceName string ` json:"name" `
}
// swagger:parameters addDataSource
type AddDataSourceParams struct {
// in:body
// required:true
Body datasources . AddDataSourceCommand
}
// swagger:parameters updateDataSourceByID
type UpdateDataSourceByIDParams struct {
// in:body
// required:true
Body datasources . UpdateDataSourceCommand
// in:path
// required:true
DatasourceID string ` json:"id" `
}
// swagger:parameters updateDataSourceByUID
type UpdateDataSourceByUIDParams struct {
// in:body
// required:true
Body datasources . UpdateDataSourceCommand
// in:path
// required:true
DatasourceUID string ` json:"uid" `
}
// swagger:response getDataSourcesResponse
type GetDataSourcesResponse struct {
// The response message
// in: body
Body dtos . DataSourceList ` json:"body" `
}
// swagger:response getDataSourceResponse
type GetDataSourceResponse struct {
// The response message
// in: body
Body dtos . DataSource ` json:"body" `
}
// swagger:response createOrUpdateDatasourceResponse
type CreateOrUpdateDatasourceResponse struct {
// The response message
// in: body
Body struct {
// ID Identifier of the new data source.
// required: true
// example: 65
ID int64 ` json:"id" `
// Name of the new data source.
// required: true
// example: My Data source
Name string ` json:"name" `
// Message Message of the deleted dashboard.
// required: true
// example: Data source added
Message string ` json:"message" `
// Datasource properties
// required: true
Datasource dtos . DataSource ` json:"datasource" `
} ` json:"body" `
}
// swagger:response getDataSourceIDResponse
type GetDataSourceIDresponse struct {
// The response message
// in: body
Body struct {
// ID Identifier of the data source.
// required: true
// example: 65
ID int64 ` json:"id" `
} ` json:"body" `
}
// swagger:response deleteDataSourceByNameResponse
type DeleteDataSourceByNameResponse struct {
// The response message
// in: body
Body struct {
// ID Identifier of the deleted data source.
// required: true
// example: 65
ID int64 ` json:"id" `
// Message Message of the deleted dashboard.
// required: true
// example: Dashboard My Dashboard deleted
Message string ` json:"message" `
} ` json:"body" `
}