2022-02-11 15:52:14 +01:00
package service
2016-12-07 11:10:42 +01:00
import (
2021-10-07 16:33:50 +02:00
"context"
2016-12-07 11:10:42 +01:00
"crypto/tls"
2022-04-25 13:57:45 -03:00
"encoding/json"
2023-07-17 19:57:19 +05:30
"errors"
2019-10-11 14:28:52 +02:00
"fmt"
2016-12-07 11:10:42 +01:00
"net/http"
2021-06-10 10:27:14 +02:00
"strconv"
2022-01-18 17:34:35 +01:00
"strings"
2016-12-07 11:10:42 +01:00
"sync"
"time"
2019-02-11 13:42:05 +01:00
2021-05-19 23:53:41 +02:00
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
2023-08-03 07:11:02 -05:00
sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
2022-03-09 11:57:50 -05:00
2021-05-19 23:53:41 +02:00
"github.com/grafana/grafana/pkg/components/simplejson"
2022-10-19 09:02:15 -04:00
"github.com/grafana/grafana/pkg/infra/db"
2021-05-19 23:53:41 +02:00
"github.com/grafana/grafana/pkg/infra/httpclient"
2022-07-12 17:27:37 -03:00
"github.com/grafana/grafana/pkg/infra/log"
2022-01-18 17:34:35 +01:00
"github.com/grafana/grafana/pkg/services/accesscontrol"
2022-03-09 11:57:50 -05:00
"github.com/grafana/grafana/pkg/services/datasources"
2022-02-17 14:03:45 +01:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
2022-11-14 21:08:10 +02:00
"github.com/grafana/grafana/pkg/services/quota"
2021-11-04 18:47:21 +02:00
"github.com/grafana/grafana/pkg/services/secrets"
2022-04-25 13:57:45 -03:00
"github.com/grafana/grafana/pkg/services/secrets/kvstore"
2021-08-17 12:16:34 +02:00
"github.com/grafana/grafana/pkg/setting"
2020-09-09 07:47:05 +02:00
)
2023-07-17 19:57:19 +05:30
const (
maxDatasourceNameLen = 190
maxDatasourceUrlLen = 255
)
2021-10-07 16:33:50 +02:00
type Service struct {
2022-08-26 10:03:38 -05:00
SQLStore Store
2022-04-25 13:57:45 -03:00
SecretsStore kvstore . SecretsKVStore
2022-02-17 14:03:45 +01:00
SecretsService secrets . Service
2022-04-01 04:26:49 -07:00
cfg * setting . Cfg
2022-02-17 14:03:45 +01:00
features featuremgmt . FeatureToggles
2022-05-10 15:48:47 +02:00
permissionsService accesscontrol . DatasourcePermissionsService
2022-04-25 10:42:09 +02:00
ac accesscontrol . AccessControl
2022-07-12 17:27:37 -03:00
logger log . Logger
2022-08-26 10:03:38 -05:00
db db . DB
2021-07-15 14:30:06 +02:00
2022-04-25 13:57:45 -03:00
ptc proxyTransportCache
2021-04-07 17:46:19 +03:00
}
2021-05-19 23:53:41 +02:00
type proxyTransportCache struct {
cache map [ int64 ] cachedRoundTripper
sync . Mutex
}
type cachedRoundTripper struct {
updated time . Time
roundTripper http . RoundTripper
}
2022-02-17 14:03:45 +01:00
func ProvideService (
2022-08-26 10:03:38 -05:00
db db . DB , secretsService secrets . Service , secretsStore kvstore . SecretsKVStore , cfg * setting . Cfg ,
2022-05-10 15:48:47 +02:00
features featuremgmt . FeatureToggles , ac accesscontrol . AccessControl , datasourcePermissionsService accesscontrol . DatasourcePermissionsService ,
2022-11-14 21:08:10 +02:00
quotaService quota . Service ,
) ( * Service , error ) {
2022-08-26 10:03:38 -05:00
dslogger := log . New ( "datasources" )
store := & SqlStore { db : db , logger : dslogger }
2021-10-07 16:33:50 +02:00
s := & Service {
2021-11-04 18:47:21 +02:00
SQLStore : store ,
2022-04-25 13:57:45 -03:00
SecretsStore : secretsStore ,
2021-11-04 18:47:21 +02:00
SecretsService : secretsService ,
2021-10-07 16:33:50 +02:00
ptc : proxyTransportCache {
cache : make ( map [ int64 ] cachedRoundTripper ) ,
} ,
2022-04-01 04:26:49 -07:00
cfg : cfg ,
2022-02-17 14:03:45 +01:00
features : features ,
2022-05-10 15:48:47 +02:00
permissionsService : datasourcePermissionsService ,
2022-04-25 10:42:09 +02:00
ac : ac ,
2022-08-26 10:03:38 -05:00
logger : dslogger ,
db : db ,
2021-10-07 16:33:50 +02:00
}
2022-05-02 09:29:30 +02:00
ac . RegisterScopeAttributeResolver ( NewNameScopeResolver ( store ) )
ac . RegisterScopeAttributeResolver ( NewIDScopeResolver ( store ) )
2022-01-18 17:34:35 +01:00
2022-11-14 21:08:10 +02:00
defaultLimits , err := readQuotaConfig ( cfg )
if err != nil {
return nil , err
}
if err := quotaService . RegisterQuotaReporter ( & quota . NewUsageReporter {
TargetSrv : datasources . QuotaTargetSrv ,
DefaultLimits : defaultLimits ,
Reporter : s . Usage ,
} ) ; err != nil {
return nil , err
}
return s , nil
}
func ( s * Service ) Usage ( ctx context . Context , scopeParams * quota . ScopeParameters ) ( * quota . Map , error ) {
return s . SQLStore . Count ( ctx , scopeParams )
2021-10-07 16:33:50 +02:00
}
2022-02-11 15:52:14 +01:00
// DataSourceRetriever interface for retrieving a datasource.
2022-01-18 17:34:35 +01:00
type DataSourceRetriever interface {
2022-02-11 15:52:14 +01:00
// GetDataSource gets a datasource.
2023-02-09 15:49:44 +01:00
GetDataSource ( ctx context . Context , query * datasources . GetDataSourceQuery ) ( * datasources . DataSource , error )
2022-01-18 17:34:35 +01:00
}
2022-05-02 09:29:30 +02:00
// NewNameScopeResolver provides an ScopeAttributeResolver able to
2022-03-24 12:21:26 +01:00
// translate a scope prefixed with "datasources:name:" into an uid based scope.
2022-05-02 09:29:30 +02:00
func NewNameScopeResolver ( db DataSourceRetriever ) ( string , accesscontrol . ScopeAttributeResolver ) {
2022-03-16 15:11:03 +01:00
prefix := datasources . ScopeProvider . GetResourceScopeName ( "" )
2022-05-02 09:29:30 +02:00
return prefix , accesscontrol . ScopeAttributeResolverFunc ( func ( ctx context . Context , orgID int64 , initialScope string ) ( [ ] string , error ) {
2022-03-11 08:50:04 +01:00
if ! strings . HasPrefix ( initialScope , prefix ) {
2022-05-02 09:29:30 +02:00
return nil , accesscontrol . ErrInvalidScope
2022-01-18 17:34:35 +01:00
}
2022-03-11 08:50:04 +01:00
dsName := initialScope [ len ( prefix ) : ]
if dsName == "" {
2022-05-02 09:29:30 +02:00
return nil , accesscontrol . ErrInvalidScope
2022-01-18 17:34:35 +01:00
}
2023-02-02 17:22:43 +01:00
query := datasources . GetDataSourceQuery { Name : dsName , OrgID : orgID }
2023-02-09 15:49:44 +01:00
dataSource , err := db . GetDataSource ( ctx , & query )
if err != nil {
2022-05-02 09:29:30 +02:00
return nil , err
2022-01-18 17:34:35 +01:00
}
2023-02-09 15:49:44 +01:00
return [ ] string { datasources . ScopeProvider . GetResourceScopeUID ( dataSource . UID ) } , nil
2022-05-02 09:29:30 +02:00
} )
2022-03-11 08:50:04 +01:00
}
2022-05-02 09:29:30 +02:00
// NewIDScopeResolver provides an ScopeAttributeResolver able to
2022-03-24 12:21:26 +01:00
// translate a scope prefixed with "datasources:id:" into an uid based scope.
2022-05-02 09:29:30 +02:00
func NewIDScopeResolver ( db DataSourceRetriever ) ( string , accesscontrol . ScopeAttributeResolver ) {
2022-03-24 12:21:26 +01:00
prefix := datasources . ScopeProvider . GetResourceScope ( "" )
2022-05-02 09:29:30 +02:00
return prefix , accesscontrol . ScopeAttributeResolverFunc ( func ( ctx context . Context , orgID int64 , initialScope string ) ( [ ] string , error ) {
2022-03-11 08:50:04 +01:00
if ! strings . HasPrefix ( initialScope , prefix ) {
2022-05-02 09:29:30 +02:00
return nil , accesscontrol . ErrInvalidScope
2022-03-11 08:50:04 +01:00
}
2022-03-24 12:21:26 +01:00
id := initialScope [ len ( prefix ) : ]
if id == "" {
2022-05-02 09:29:30 +02:00
return nil , accesscontrol . ErrInvalidScope
2022-03-11 08:50:04 +01:00
}
2022-03-24 12:21:26 +01:00
dsID , err := strconv . ParseInt ( id , 10 , 64 )
if err != nil {
2022-05-02 09:29:30 +02:00
return nil , accesscontrol . ErrInvalidScope
2022-03-24 12:21:26 +01:00
}
2023-02-02 17:22:43 +01:00
query := datasources . GetDataSourceQuery { ID : dsID , OrgID : orgID }
2023-02-09 15:49:44 +01:00
dataSource , err := db . GetDataSource ( ctx , & query )
if err != nil {
2022-05-02 09:29:30 +02:00
return nil , err
2022-03-11 08:50:04 +01:00
}
2023-02-09 15:49:44 +01:00
return [ ] string { datasources . ScopeProvider . GetResourceScopeUID ( dataSource . UID ) } , nil
2022-05-02 09:29:30 +02:00
} )
2022-01-18 17:34:35 +01:00
}
2023-02-09 15:49:44 +01:00
func ( s * Service ) GetDataSource ( ctx context . Context , query * datasources . GetDataSourceQuery ) ( * datasources . DataSource , error ) {
2021-10-18 16:06:19 +01:00
return s . SQLStore . GetDataSource ( ctx , query )
2021-05-19 23:53:41 +02:00
}
2023-02-09 15:49:44 +01:00
func ( s * Service ) GetDataSources ( ctx context . Context , query * datasources . GetDataSourcesQuery ) ( [ ] * datasources . DataSource , error ) {
2021-11-26 18:10:36 +01:00
return s . SQLStore . GetDataSources ( ctx , query )
2021-10-07 16:33:50 +02:00
}
2023-03-20 19:18:21 +01:00
func ( s * Service ) GetAllDataSources ( ctx context . Context , query * datasources . GetAllDataSourcesQuery ) ( res [ ] * datasources . DataSource , err error ) {
2022-07-12 17:27:37 -03:00
return s . SQLStore . GetAllDataSources ( ctx , query )
}
2023-02-09 15:49:44 +01:00
func ( s * Service ) GetDataSourcesByType ( ctx context . Context , query * datasources . GetDataSourcesByTypeQuery ) ( [ ] * datasources . DataSource , error ) {
2021-11-26 18:10:36 +01:00
return s . SQLStore . GetDataSourcesByType ( ctx , query )
2021-10-07 16:33:50 +02:00
}
2023-02-09 15:49:44 +01:00
func ( s * Service ) AddDataSource ( ctx context . Context , cmd * datasources . AddDataSourceCommand ) ( * datasources . DataSource , error ) {
var dataSource * datasources . DataSource
2023-07-17 19:57:19 +05:30
if err := validateFields ( cmd . Name , cmd . URL ) ; err != nil {
return dataSource , err
}
2023-02-09 15:49:44 +01:00
return dataSource , s . db . InTransaction ( ctx , func ( ctx context . Context ) error {
2022-06-16 12:26:57 -04:00
var err error
2022-02-17 14:03:45 +01:00
2022-07-12 17:27:37 -03:00
cmd . EncryptedSecureJsonData = make ( map [ string ] [ ] byte )
if ! s . features . IsEnabled ( featuremgmt . FlagDisableSecretsCompatibility ) {
cmd . EncryptedSecureJsonData , err = s . SecretsService . EncryptJsonData ( ctx , cmd . SecureJsonData , secrets . WithoutScope ( ) )
if err != nil {
return err
}
2022-03-21 17:16:05 +01:00
}
2022-06-16 12:26:57 -04:00
cmd . UpdateSecretFn = func ( ) error {
2022-07-12 17:27:37 -03:00
secret , err := json . Marshal ( cmd . SecureJsonData )
if err != nil {
return err
}
2023-02-02 17:22:43 +01:00
return s . SecretsStore . Set ( ctx , cmd . OrgID , cmd . Name , kvstore . DataSourceSecretType , string ( secret ) )
2022-03-21 17:16:05 +01:00
}
2022-06-16 12:26:57 -04:00
2023-02-09 15:49:44 +01:00
dataSource , err = s . SQLStore . AddDataSource ( ctx , cmd )
if err != nil {
2022-02-17 14:03:45 +01:00
return err
}
2023-08-25 14:19:58 +01:00
// This belongs in Data source permissions, and we probably want
// to do this with a hook in the store and rollback on fail.
// We can't use events, because there's no way to communicate
// failure, and we want "not being able to set default perms"
// to fail the creation.
permissions := [ ] accesscontrol . SetResourcePermissionCommand {
{ BuiltinRole : "Viewer" , Permission : "Query" } ,
{ BuiltinRole : "Editor" , Permission : "Query" } ,
2022-06-16 12:26:57 -04:00
}
2023-08-25 14:19:58 +01:00
if cmd . UserID != 0 {
permissions = append ( permissions , accesscontrol . SetResourcePermissionCommand { UserID : cmd . UserID , Permission : "Edit" } )
}
_ , err = s . permissionsService . SetPermissions ( ctx , cmd . OrgID , dataSource . UID , permissions ... )
return err
2022-06-16 12:26:57 -04:00
} )
2021-10-07 16:33:50 +02:00
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) DeleteDataSource ( ctx context . Context , cmd * datasources . DeleteDataSourceCommand ) error {
2022-08-26 10:03:38 -05:00
return s . db . InTransaction ( ctx , func ( ctx context . Context ) error {
2022-06-16 12:26:57 -04:00
cmd . UpdateSecretFn = func ( ) error {
2022-08-25 18:04:44 -03:00
return s . SecretsStore . Del ( ctx , cmd . OrgID , cmd . Name , kvstore . DataSourceSecretType )
2022-06-16 12:26:57 -04:00
}
return s . SQLStore . DeleteDataSource ( ctx , cmd )
} )
2021-10-07 16:33:50 +02:00
}
2023-02-09 15:49:44 +01:00
func ( s * Service ) UpdateDataSource ( ctx context . Context , cmd * datasources . UpdateDataSourceCommand ) ( * datasources . DataSource , error ) {
var dataSource * datasources . DataSource
2023-07-17 19:57:19 +05:30
if err := validateFields ( cmd . Name , cmd . URL ) ; err != nil {
return dataSource , err
}
2023-02-09 15:49:44 +01:00
return dataSource , s . db . InTransaction ( ctx , func ( ctx context . Context ) error {
2022-06-16 12:26:57 -04:00
var err error
2021-10-07 16:33:50 +02:00
2022-06-27 12:23:15 -04:00
query := & datasources . GetDataSourceQuery {
2023-02-02 17:22:43 +01:00
ID : cmd . ID ,
OrgID : cmd . OrgID ,
2022-06-16 12:26:57 -04:00
}
2023-02-09 15:49:44 +01:00
dataSource , err = s . SQLStore . GetDataSource ( ctx , query )
2022-06-16 12:26:57 -04:00
if err != nil {
return err
}
2022-05-02 11:29:13 -03:00
2023-07-17 19:57:19 +05:30
if cmd . Name != "" && cmd . Name != dataSource . Name {
query := & datasources . GetDataSourceQuery {
Name : cmd . Name ,
OrgID : cmd . OrgID ,
}
exist , err := s . SQLStore . GetDataSource ( ctx , query )
if exist != nil {
return datasources . ErrDataSourceNameExists
}
if err != nil && ! errors . Is ( err , datasources . ErrDataSourceNotFound ) {
return err
}
}
2023-02-09 15:49:44 +01:00
err = s . fillWithSecureJSONData ( ctx , cmd , dataSource )
2022-06-16 12:26:57 -04:00
if err != nil {
return err
}
2022-04-25 13:57:45 -03:00
2023-02-02 17:22:43 +01:00
if cmd . OrgID > 0 && cmd . Name != "" {
2022-07-12 17:27:37 -03:00
cmd . UpdateSecretFn = func ( ) error {
secret , err := json . Marshal ( cmd . SecureJsonData )
if err != nil {
return err
}
2022-04-25 13:57:45 -03:00
2023-02-09 15:49:44 +01:00
if dataSource . Name != cmd . Name {
err := s . SecretsStore . Rename ( ctx , cmd . OrgID , dataSource . Name , kvstore . DataSourceSecretType , cmd . Name )
2022-07-12 17:27:37 -03:00
if err != nil {
return err
}
}
2022-06-16 12:26:57 -04:00
2023-02-02 17:22:43 +01:00
return s . SecretsStore . Set ( ctx , cmd . OrgID , cmd . Name , kvstore . DataSourceSecretType , string ( secret ) )
2022-07-12 17:27:37 -03:00
}
2022-06-16 12:26:57 -04:00
}
2022-05-02 11:29:13 -03:00
2023-02-09 15:49:44 +01:00
dataSource , err = s . SQLStore . UpdateDataSource ( ctx , cmd )
return err
2022-06-16 12:26:57 -04:00
} )
2021-10-07 16:33:50 +02:00
}
2023-02-09 15:49:44 +01:00
func ( s * Service ) GetDefaultDataSource ( ctx context . Context , query * datasources . GetDefaultDataSourceQuery ) ( * datasources . DataSource , error ) {
2021-11-26 18:10:36 +01:00
return s . SQLStore . GetDefaultDataSource ( ctx , query )
2021-10-07 16:33:50 +02:00
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) GetHTTPClient ( ctx context . Context , ds * datasources . DataSource , provider httpclient . Provider ) ( * http . Client , error ) {
2022-04-25 13:57:45 -03:00
transport , err := s . GetHTTPTransport ( ctx , ds , provider )
2016-12-07 11:10:42 +01:00
if err != nil {
return nil , err
}
return & http . Client {
2021-10-07 16:33:50 +02:00
Timeout : s . getTimeout ( ds ) ,
2016-12-07 11:10:42 +01:00
Transport : transport ,
} , nil
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) GetHTTPTransport ( ctx context . Context , ds * datasources . DataSource , provider httpclient . Provider ,
2021-10-07 16:33:50 +02:00
customMiddlewares ... sdkhttpclient . Middleware ) ( http . RoundTripper , error ) {
s . ptc . Lock ( )
defer s . ptc . Unlock ( )
2016-12-07 11:10:42 +01:00
2023-02-02 17:22:43 +01:00
if t , present := s . ptc . cache [ ds . ID ] ; present && ds . Updated . Equal ( t . updated ) {
2021-05-19 23:53:41 +02:00
return t . roundTripper , nil
2016-12-07 11:10:42 +01:00
}
2022-04-25 13:57:45 -03:00
opts , err := s . httpClientOptions ( ctx , ds )
2021-07-22 13:43:10 -07:00
if err != nil {
return nil , err
}
2022-04-01 04:26:49 -07:00
opts . Middlewares = append ( opts . Middlewares , customMiddlewares ... )
2021-05-27 12:43:21 +02:00
2021-07-22 13:43:10 -07:00
rt , err := provider . GetTransport ( * opts )
2019-01-28 19:38:56 +01:00
if err != nil {
return nil , err
2017-09-28 14:10:14 +01:00
}
2023-02-02 17:22:43 +01:00
s . ptc . cache [ ds . ID ] = cachedRoundTripper {
2021-05-19 23:53:41 +02:00
roundTripper : rt ,
updated : ds . Updated ,
2016-12-07 11:10:42 +01:00
}
2021-05-19 23:53:41 +02:00
return rt , nil
}
2020-10-08 10:03:20 +02:00
2022-06-27 12:23:15 -04:00
func ( s * Service ) GetTLSConfig ( ctx context . Context , ds * datasources . DataSource , httpClientProvider httpclient . Provider ) ( * tls . Config , error ) {
2022-04-25 13:57:45 -03:00
opts , err := s . httpClientOptions ( ctx , ds )
2021-10-07 16:33:50 +02:00
if err != nil {
return nil , err
}
return httpClientProvider . GetTLSConfig ( * opts )
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) DecryptedValues ( ctx context . Context , ds * datasources . DataSource ) ( map [ string ] string , error ) {
2022-04-25 13:57:45 -03:00
decryptedValues := make ( map [ string ] string )
2023-02-02 17:22:43 +01:00
secret , exist , err := s . SecretsStore . Get ( ctx , ds . OrgID , ds . Name , kvstore . DataSourceSecretType )
2022-04-25 13:57:45 -03:00
if err != nil {
return nil , err
}
2021-10-07 16:33:50 +02:00
2022-04-25 13:57:45 -03:00
if exist {
2022-06-01 06:45:43 -07:00
err = json . Unmarshal ( [ ] byte ( secret ) , & decryptedValues )
2022-07-12 17:27:37 -03:00
if err != nil {
2023-09-04 22:25:43 +02:00
s . logger . Debug ( "Failed to unmarshal secret value, using legacy secrets" , "err" , err )
2022-07-12 17:27:37 -03:00
}
2022-06-01 06:45:43 -07:00
}
2022-07-12 17:27:37 -03:00
if ! exist || err != nil {
decryptedValues , err = s . decryptLegacySecrets ( ctx , ds )
2022-04-25 13:57:45 -03:00
if err != nil {
return nil , err
}
2021-10-07 16:33:50 +02:00
}
2022-04-25 13:57:45 -03:00
return decryptedValues , nil
}
2022-07-12 17:27:37 -03:00
func ( s * Service ) decryptLegacySecrets ( ctx context . Context , ds * datasources . DataSource ) ( map [ string ] string , error ) {
2022-06-01 06:45:43 -07:00
secureJsonData := make ( map [ string ] string )
for k , v := range ds . SecureJsonData {
decrypted , err := s . SecretsService . Decrypt ( ctx , v )
if err != nil {
return nil , err
}
secureJsonData [ k ] = string ( decrypted )
2021-10-07 16:33:50 +02:00
}
2022-07-12 17:27:37 -03:00
return secureJsonData , nil
2021-10-07 16:33:50 +02:00
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) DecryptedValue ( ctx context . Context , ds * datasources . DataSource , key string ) ( string , bool , error ) {
2022-04-25 13:57:45 -03:00
values , err := s . DecryptedValues ( ctx , ds )
if err != nil {
return "" , false , err
}
value , exists := values [ key ]
return value , exists , nil
2021-10-07 16:33:50 +02:00
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) DecryptedBasicAuthPassword ( ctx context . Context , ds * datasources . DataSource ) ( string , error ) {
2022-04-25 13:57:45 -03:00
value , ok , err := s . DecryptedValue ( ctx , ds , "basicAuthPassword" )
if ok {
return value , nil
2021-10-07 16:33:50 +02:00
}
2022-06-03 17:38:22 +02:00
return "" , err
2021-10-07 16:33:50 +02:00
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) DecryptedPassword ( ctx context . Context , ds * datasources . DataSource ) ( string , error ) {
2022-04-25 13:57:45 -03:00
value , ok , err := s . DecryptedValue ( ctx , ds , "password" )
if ok {
return value , nil
2021-10-07 16:33:50 +02:00
}
2022-06-03 17:38:22 +02:00
return "" , err
2021-10-07 16:33:50 +02:00
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) httpClientOptions ( ctx context . Context , ds * datasources . DataSource ) ( * sdkhttpclient . Options , error ) {
2022-04-25 13:57:45 -03:00
tlsOptions , err := s . dsTLSOptions ( ctx , ds )
if err != nil {
return nil , err
}
2021-07-07 13:13:53 +03:00
timeouts := & sdkhttpclient . TimeoutOptions {
2021-10-07 16:33:50 +02:00
Timeout : s . getTimeout ( ds ) ,
2021-07-15 14:30:06 +02:00
DialTimeout : sdkhttpclient . DefaultTimeoutOptions . DialTimeout ,
KeepAlive : sdkhttpclient . DefaultTimeoutOptions . KeepAlive ,
TLSHandshakeTimeout : sdkhttpclient . DefaultTimeoutOptions . TLSHandshakeTimeout ,
ExpectContinueTimeout : sdkhttpclient . DefaultTimeoutOptions . ExpectContinueTimeout ,
MaxConnsPerHost : sdkhttpclient . DefaultTimeoutOptions . MaxConnsPerHost ,
MaxIdleConns : sdkhttpclient . DefaultTimeoutOptions . MaxIdleConns ,
MaxIdleConnsPerHost : sdkhttpclient . DefaultTimeoutOptions . MaxIdleConnsPerHost ,
IdleConnTimeout : sdkhttpclient . DefaultTimeoutOptions . IdleConnTimeout ,
2021-07-07 13:13:53 +03:00
}
2022-04-25 13:57:45 -03:00
decryptedValues , err := s . DecryptedValues ( ctx , ds )
if err != nil {
return nil , err
}
2021-07-22 13:43:10 -07:00
opts := & sdkhttpclient . Options {
2021-07-07 13:13:53 +03:00
Timeouts : timeouts ,
2022-04-25 13:57:45 -03:00
Headers : s . getCustomHeaders ( ds . JsonData , decryptedValues ) ,
2021-05-19 23:53:41 +02:00
Labels : map [ string ] string {
2022-07-21 09:46:47 -04:00
"datasource_type" : ds . Type ,
2021-05-19 23:53:41 +02:00
"datasource_name" : ds . Name ,
2023-02-02 17:22:43 +01:00
"datasource_uid" : ds . UID ,
2021-05-19 23:53:41 +02:00
} ,
TLS : & tlsOptions ,
2020-10-08 10:03:20 +02:00
}
2021-05-19 23:53:41 +02:00
if ds . JsonData != nil {
opts . CustomOptions = ds . JsonData . MustMap ( )
2023-01-19 09:49:45 -06:00
// allow the plugin sdk to get the json data in JSONDataFromHTTPClientOptions
2023-08-30 08:46:47 -07:00
deepJsonDataCopy := make ( map [ string ] any , len ( opts . CustomOptions ) )
2023-01-31 12:35:36 +01:00
for k , v := range opts . CustomOptions {
2023-03-08 12:21:01 -06:00
deepJsonDataCopy [ k ] = v
2023-01-31 12:35:36 +01:00
}
2023-03-08 12:21:01 -06:00
opts . CustomOptions [ "grafanaData" ] = deepJsonDataCopy
2019-10-11 14:28:52 +02:00
}
2021-05-19 23:53:41 +02:00
if ds . BasicAuth {
2022-04-25 13:57:45 -03:00
password , err := s . DecryptedBasicAuthPassword ( ctx , ds )
if err != nil {
return opts , err
}
2021-05-19 23:53:41 +02:00
opts . BasicAuth = & sdkhttpclient . BasicAuthOptions {
User : ds . BasicAuthUser ,
2022-04-25 13:57:45 -03:00
Password : password ,
2021-05-19 23:53:41 +02:00
}
} else if ds . User != "" {
2022-04-25 13:57:45 -03:00
password , err := s . DecryptedPassword ( ctx , ds )
if err != nil {
return opts , err
}
2021-05-19 23:53:41 +02:00
opts . BasicAuth = & sdkhttpclient . BasicAuthOptions {
User : ds . User ,
2022-04-25 13:57:45 -03:00
Password : password ,
2021-05-19 23:53:41 +02:00
}
2019-01-28 19:38:56 +01:00
}
2023-08-03 07:11:02 -05:00
if ds . JsonData != nil && ds . JsonData . Get ( "enableSecureSocksProxy" ) . MustBool ( false ) {
proxyOpts := & sdkproxy . Options {
Enabled : true ,
Auth : & sdkproxy . AuthOptions {
Username : ds . JsonData . Get ( "secureSocksProxyUsername" ) . MustString ( ds . UID ) ,
} ,
Timeouts : & sdkproxy . DefaultTimeoutOptions ,
}
if val , exists , err := s . DecryptedValue ( ctx , ds , "secureSocksProxyPassword" ) ; err == nil && exists {
proxyOpts . Auth . Password = val
}
if val , err := ds . JsonData . Get ( "timeout" ) . Float64 ( ) ; err == nil {
proxyOpts . Timeouts . Timeout = time . Duration ( val ) * time . Second
}
if val , err := ds . JsonData . Get ( "keepAlive" ) . Float64 ( ) ; err == nil {
proxyOpts . Timeouts . KeepAlive = time . Duration ( val ) * time . Second
}
opts . ProxyOptions = proxyOpts
}
2021-08-17 12:16:34 +02:00
if ds . JsonData != nil && ds . JsonData . Get ( "sigV4Auth" ) . MustBool ( false ) && setting . SigV4AuthEnabled {
2021-05-19 23:53:41 +02:00
opts . SigV4 = & sdkhttpclient . SigV4Config {
2022-12-14 20:22:26 +01:00
Service : awsServiceNamespace ( ds . Type , ds . JsonData ) ,
2021-02-01 16:07:27 +01:00
Region : ds . JsonData . Get ( "sigV4Region" ) . MustString ( ) ,
AssumeRoleARN : ds . JsonData . Get ( "sigV4AssumeRoleArn" ) . MustString ( ) ,
AuthType : ds . JsonData . Get ( "sigV4AuthType" ) . MustString ( ) ,
ExternalID : ds . JsonData . Get ( "sigV4ExternalId" ) . MustString ( ) ,
Profile : ds . JsonData . Get ( "sigV4Profile" ) . MustString ( ) ,
2021-05-19 23:53:41 +02:00
}
2022-04-25 13:57:45 -03:00
if val , exists , err := s . DecryptedValue ( ctx , ds , "sigV4AccessKey" ) ; err == nil {
if exists {
opts . SigV4 . AccessKey = val
}
} else {
return opts , err
2021-05-19 23:53:41 +02:00
}
2022-04-25 13:57:45 -03:00
if val , exists , err := s . DecryptedValue ( ctx , ds , "sigV4SecretKey" ) ; err == nil {
if exists {
opts . SigV4 . SecretKey = val
}
} else {
return opts , err
2021-05-19 23:53:41 +02:00
}
}
2021-07-22 13:43:10 -07:00
return opts , nil
2020-10-08 10:03:20 +02:00
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) dsTLSOptions ( ctx context . Context , ds * datasources . DataSource ) ( sdkhttpclient . TLSOptions , error ) {
2019-01-28 19:38:56 +01:00
var tlsSkipVerify , tlsClientAuth , tlsAuthWithCACert bool
2020-12-10 08:07:05 -07:00
var serverName string
2019-01-28 19:38:56 +01:00
if ds . JsonData != nil {
tlsClientAuth = ds . JsonData . Get ( "tlsAuth" ) . MustBool ( false )
tlsAuthWithCACert = ds . JsonData . Get ( "tlsAuthWithCACert" ) . MustBool ( false )
tlsSkipVerify = ds . JsonData . Get ( "tlsSkipVerify" ) . MustBool ( false )
2020-12-10 08:07:05 -07:00
serverName = ds . JsonData . Get ( "serverName" ) . MustString ( )
2019-01-28 19:38:56 +01:00
}
2021-05-19 23:53:41 +02:00
opts := sdkhttpclient . TLSOptions {
2019-01-28 19:38:56 +01:00
InsecureSkipVerify : tlsSkipVerify ,
2020-12-10 08:07:05 -07:00
ServerName : serverName ,
2019-01-28 19:38:56 +01:00
}
2017-09-28 11:04:01 +01:00
if tlsClientAuth || tlsAuthWithCACert {
2021-05-19 23:53:41 +02:00
if tlsAuthWithCACert {
2022-04-25 13:57:45 -03:00
if val , exists , err := s . DecryptedValue ( ctx , ds , "tlsCACert" ) ; err == nil {
if exists && len ( val ) > 0 {
opts . CACertificate = val
}
} else {
return opts , err
2016-12-07 11:10:42 +01:00
}
}
2017-09-28 11:04:01 +01:00
if tlsClientAuth {
2022-04-25 13:57:45 -03:00
if val , exists , err := s . DecryptedValue ( ctx , ds , "tlsClientCert" ) ; err == nil {
fmt . Print ( "\n\n\n\n" , val , exists , err , "\n\n\n\n" )
if exists && len ( val ) > 0 {
opts . ClientCertificate = val
}
} else {
return opts , err
2021-05-19 23:53:41 +02:00
}
2022-04-25 13:57:45 -03:00
if val , exists , err := s . DecryptedValue ( ctx , ds , "tlsClientKey" ) ; err == nil {
if exists && len ( val ) > 0 {
opts . ClientKey = val
}
} else {
return opts , err
2017-09-28 11:04:01 +01:00
}
2016-12-07 11:10:42 +01:00
}
}
2022-04-25 13:57:45 -03:00
return opts , nil
2021-05-19 23:53:41 +02:00
}
2022-06-27 12:23:15 -04:00
func ( s * Service ) getTimeout ( ds * datasources . DataSource ) time . Duration {
2021-10-07 16:33:50 +02:00
timeout := 0
if ds . JsonData != nil {
timeout = ds . JsonData . Get ( "timeout" ) . MustInt ( )
if timeout <= 0 {
if timeoutStr := ds . JsonData . Get ( "timeout" ) . MustString ( ) ; timeoutStr != "" {
if t , err := strconv . Atoi ( timeoutStr ) ; err == nil {
timeout = t
}
}
}
2021-07-22 13:43:10 -07:00
}
2021-10-07 16:33:50 +02:00
if timeout <= 0 {
return sdkhttpclient . DefaultTimeoutOptions . Timeout
}
return time . Duration ( timeout ) * time . Second
2016-12-07 11:10:42 +01:00
}
2019-10-11 14:28:52 +02:00
// getCustomHeaders returns a map with all the to be set headers
// The map key represents the HeaderName and the value represents this header's value
2021-10-07 16:33:50 +02:00
func ( s * Service ) getCustomHeaders ( jsonData * simplejson . Json , decryptedValues map [ string ] string ) map [ string ] string {
2019-10-11 14:28:52 +02:00
headers := make ( map [ string ] string )
2021-05-19 23:53:41 +02:00
if jsonData == nil {
2019-10-11 14:28:52 +02:00
return headers
}
2022-09-20 18:31:08 +01:00
index := 0
2019-10-11 14:28:52 +02:00
for {
2022-09-20 18:31:08 +01:00
index ++
2023-04-19 17:04:30 +02:00
headerNameSuffix := fmt . Sprintf ( "%s%d" , datasources . CustomHeaderName , index )
headerValueSuffix := fmt . Sprintf ( "%s%d" , datasources . CustomHeaderValue , index )
2019-10-11 14:28:52 +02:00
2021-05-19 23:53:41 +02:00
key := jsonData . Get ( headerNameSuffix ) . MustString ( )
2019-10-11 14:28:52 +02:00
if key == "" {
// No (more) header values are available
break
}
2022-09-20 18:31:08 +01:00
// skip a header with name that corresponds to auth proxy header's name
// to make sure that data source proxy isn't used to circumvent auth proxy.
// For more context take a look at CVE-2022-35957
if s . cfg . AuthProxyEnabled && http . CanonicalHeaderKey ( key ) == http . CanonicalHeaderKey ( s . cfg . AuthProxyHeaderName ) {
continue
}
2021-05-19 23:53:41 +02:00
if val , ok := decryptedValues [ headerValueSuffix ] ; ok {
2019-10-11 14:28:52 +02:00
headers [ key ] = val
}
}
return headers
}
2019-11-22 14:21:23 +01:00
2022-12-14 20:22:26 +01:00
func awsServiceNamespace ( dsType string , jsonData * simplejson . Json ) string {
2021-02-01 16:07:27 +01:00
switch dsType {
2022-12-14 20:22:26 +01:00
case datasources . DS_ES , datasources . DS_ES_OPEN_DISTRO :
2021-02-01 16:07:27 +01:00
return "es"
2022-12-14 20:22:26 +01:00
case datasources . DS_ES_OPENSEARCH :
serverless := jsonData . Get ( "serverless" ) . MustBool ( )
if serverless {
return "aoss"
} else {
return "es"
}
2022-06-27 12:23:15 -04:00
case datasources . DS_PROMETHEUS , datasources . DS_ALERTMANAGER :
2021-02-01 16:07:27 +01:00
return "aps"
default :
panic ( fmt . Sprintf ( "Unsupported datasource %q" , dsType ) )
}
}
2022-05-02 11:29:13 -03:00
2022-06-27 12:23:15 -04:00
func ( s * Service ) fillWithSecureJSONData ( ctx context . Context , cmd * datasources . UpdateDataSourceCommand , ds * datasources . DataSource ) error {
2022-05-02 11:29:13 -03:00
decrypted , err := s . DecryptedValues ( ctx , ds )
if err != nil {
return err
}
if cmd . SecureJsonData == nil {
cmd . SecureJsonData = make ( map [ string ] string )
}
2023-07-27 11:11:43 +02:00
if ! cmd . IgnoreOldSecureJsonData {
for k , v := range decrypted {
if _ , ok := cmd . SecureJsonData [ k ] ; ! ok {
cmd . SecureJsonData [ k ] = v
}
2022-05-02 11:29:13 -03:00
}
}
2022-07-12 17:27:37 -03:00
cmd . EncryptedSecureJsonData = make ( map [ string ] [ ] byte )
if ! s . features . IsEnabled ( featuremgmt . FlagDisableSecretsCompatibility ) {
cmd . EncryptedSecureJsonData , err = s . SecretsService . EncryptJsonData ( ctx , cmd . SecureJsonData , secrets . WithoutScope ( ) )
if err != nil {
return err
}
2022-06-01 06:45:43 -07:00
}
2022-05-02 11:29:13 -03:00
return nil
}
2022-11-14 21:08:10 +02:00
2023-07-17 19:57:19 +05:30
func validateFields ( name , url string ) error {
if len ( name ) > maxDatasourceNameLen {
return datasources . ErrDataSourceNameInvalid . Errorf ( "max length is %d" , maxDatasourceNameLen )
}
if len ( url ) > maxDatasourceUrlLen {
return datasources . ErrDataSourceURLInvalid . Errorf ( "max length is %d" , maxDatasourceUrlLen )
}
return nil
}
2022-11-14 21:08:10 +02:00
func readQuotaConfig ( cfg * setting . Cfg ) ( * quota . Map , error ) {
limits := & quota . Map { }
if cfg == nil {
return limits , nil
}
globalQuotaTag , err := quota . NewTag ( datasources . QuotaTargetSrv , datasources . QuotaTarget , quota . GlobalScope )
if err != nil {
return limits , err
}
orgQuotaTag , err := quota . NewTag ( datasources . QuotaTargetSrv , datasources . QuotaTarget , quota . OrgScope )
if err != nil {
return limits , err
}
limits . Set ( globalQuotaTag , cfg . Quota . Global . DataSource )
limits . Set ( orgQuotaTag , cfg . Quota . Org . DataSource )
return limits , nil
}
2023-04-19 17:04:30 +02:00
// CustomerHeaders returns the custom headers specified in the datasource. The context is used for the decryption operation that might use the store, so consider setting an acceptable timeout for your use case.
func ( s * Service ) CustomHeaders ( ctx context . Context , ds * datasources . DataSource ) ( map [ string ] string , error ) {
values , err := s . SecretsService . DecryptJsonData ( ctx , ds . SecureJsonData )
if err != nil {
return nil , fmt . Errorf ( "failed to get custom headers: %w" , err )
}
return s . getCustomHeaders ( ds . JsonData , values ) , nil
}