2022-07-25 09:19:07 -05:00
package correlations
import (
"context"
2023-09-13 08:10:09 -05:00
"xorm.io/core"
2022-10-19 08:02:15 -05:00
"github.com/grafana/grafana/pkg/infra/db"
2022-07-25 09:19:07 -05:00
"github.com/grafana/grafana/pkg/services/datasources"
2023-03-21 15:27:25 -05:00
"github.com/grafana/grafana/pkg/services/quota"
2022-07-25 09:19:07 -05:00
"github.com/grafana/grafana/pkg/util"
)
// createCorrelation adds a correlation
func ( s CorrelationsService ) createCorrelation ( ctx context . Context , cmd CreateCorrelationCommand ) ( Correlation , error ) {
correlation := Correlation {
UID : util . GenerateShortUID ( ) ,
2023-08-24 02:39:30 -05:00
OrgID : cmd . OrgId ,
2022-07-25 09:19:07 -05:00
SourceUID : cmd . SourceUID ,
TargetUID : cmd . TargetUID ,
Label : cmd . Label ,
Description : cmd . Description ,
2022-09-27 04:08:02 -05:00
Config : cmd . Config ,
2023-09-13 08:10:09 -05:00
Provisioned : cmd . Provisioned ,
2022-07-25 09:19:07 -05:00
}
2022-10-19 08:02:15 -05:00
err := s . SQLStore . WithTransactionalDbSession ( ctx , func ( session * db . Session ) error {
2022-07-25 09:19:07 -05:00
var err error
query := & datasources . GetDataSourceQuery {
2023-02-02 10:22:43 -06:00
OrgID : cmd . OrgId ,
UID : cmd . SourceUID ,
2022-07-25 09:19:07 -05:00
}
2023-09-13 08:10:09 -05:00
_ , err = s . DataSourceService . GetDataSource ( ctx , query )
2023-02-09 08:49:44 -06:00
if err != nil {
2022-07-25 09:19:07 -05:00
return ErrSourceDataSourceDoesNotExists
}
2022-10-04 03:39:55 -05:00
if cmd . TargetUID != nil {
2023-02-09 08:49:44 -06:00
if _ , err = s . DataSourceService . GetDataSource ( ctx , & datasources . GetDataSourceQuery {
2023-02-02 10:22:43 -06:00
OrgID : cmd . OrgId ,
UID : * cmd . TargetUID ,
2022-10-04 03:39:55 -05:00
} ) ; err != nil {
return ErrTargetDataSourceDoesNotExists
}
2022-07-25 09:19:07 -05:00
}
_ , err = session . Insert ( correlation )
if err != nil {
return err
}
return nil
} )
if err != nil {
return Correlation { } , err
}
return correlation , nil
}
2022-07-27 03:07:58 -05:00
func ( s CorrelationsService ) deleteCorrelation ( ctx context . Context , cmd DeleteCorrelationCommand ) error {
2022-10-19 08:02:15 -05:00
return s . SQLStore . WithDbSession ( ctx , func ( session * db . Session ) error {
2022-07-27 03:07:58 -05:00
query := & datasources . GetDataSourceQuery {
2023-02-02 10:22:43 -06:00
OrgID : cmd . OrgId ,
UID : cmd . SourceUID ,
2022-07-27 03:07:58 -05:00
}
2023-09-13 08:10:09 -05:00
_ , err := s . DataSourceService . GetDataSource ( ctx , query )
2023-02-09 08:49:44 -06:00
if err != nil {
2022-07-27 03:07:58 -05:00
return ErrSourceDataSourceDoesNotExists
}
2023-09-13 08:10:09 -05:00
correlation , err := s . GetCorrelation ( ctx , GetCorrelationQuery ( cmd ) )
if err != nil {
return err
}
if correlation . Provisioned {
return ErrCorrelationReadOnly
2022-07-27 03:07:58 -05:00
}
deletedCount , err := session . Delete ( & Correlation { UID : cmd . UID , SourceUID : cmd . SourceUID } )
if deletedCount == 0 {
return ErrCorrelationNotFound
}
return err
} )
}
2022-08-03 08:18:51 -05:00
func ( s CorrelationsService ) updateCorrelation ( ctx context . Context , cmd UpdateCorrelationCommand ) ( Correlation , error ) {
correlation := Correlation {
UID : cmd . UID ,
SourceUID : cmd . SourceUID ,
2023-08-24 02:39:30 -05:00
OrgID : cmd . OrgId ,
2022-08-03 08:18:51 -05:00
}
2022-10-19 08:02:15 -05:00
err := s . SQLStore . WithTransactionalDbSession ( ctx , func ( session * db . Session ) error {
2022-08-03 08:18:51 -05:00
query := & datasources . GetDataSourceQuery {
2023-02-02 10:22:43 -06:00
OrgID : cmd . OrgId ,
UID : cmd . SourceUID ,
2022-08-03 08:18:51 -05:00
}
2023-09-13 08:10:09 -05:00
_ , err := s . DataSourceService . GetDataSource ( ctx , query )
2023-02-09 08:49:44 -06:00
if err != nil {
2022-08-03 08:18:51 -05:00
return ErrSourceDataSourceDoesNotExists
}
2022-10-10 08:36:14 -05:00
found , err := session . Get ( & correlation )
if ! found {
return ErrCorrelationNotFound
}
if err != nil {
return err
}
2023-09-13 08:10:09 -05:00
if correlation . Provisioned {
return ErrCorrelationReadOnly
}
2022-10-10 08:36:14 -05:00
2022-08-03 08:18:51 -05:00
if cmd . Label != nil {
2022-10-10 08:36:14 -05:00
correlation . Label = * cmd . Label
2022-08-03 08:18:51 -05:00
session . MustCols ( "label" )
}
if cmd . Description != nil {
2022-10-10 08:36:14 -05:00
correlation . Description = * cmd . Description
2022-08-03 08:18:51 -05:00
session . MustCols ( "description" )
}
2022-10-10 08:36:14 -05:00
if cmd . Config != nil {
session . MustCols ( "config" )
if cmd . Config . Field != nil {
correlation . Config . Field = * cmd . Config . Field
}
if cmd . Config . Type != nil {
correlation . Config . Type = * cmd . Config . Type
}
if cmd . Config . Target != nil {
correlation . Config . Target = * cmd . Config . Target
}
Explore: Add transformations to correlation data links (#61799)
* bring in source from database
* bring in transformations from database
* add regex transformations to scopevar
* Consolidate types, add better example, cleanup
* Add var only if match
* Change ScopedVar to not require text, do not leak transformation-made variables between links
* Add mappings and start implementing logfmt
* Add mappings and start implementing logfmt
* Remove mappings, turn off global regex
* Add example yaml and omit transformations if empty
* Fix the yaml
* Add logfmt transformation
* Cleanup transformations and yaml
* add transformation field to FE types and use it, safeStringify logfmt values
* Add tests, only safe stringify if non-string, fix bug with safe stringify where it would return empty string with false value
* Add test for transformation field
* Do not add null transformations object
* Break out transformation logic, add tests to backend code
* Fix lint errors I understand 😅
* Fix the backend lint error
* Remove unnecessary code and mark new Transformations object as internal
* Add support for named capture groups
* Remove type assertion
* Remove variable name from transformation
* Add test for overriding regexes
* Add back variable name field, but change to mapValue
* fix go api test
* Change transformation types to enum, add better provisioning checks for bad type name and format
* Check for expression with regex transformations
2023-02-22 06:53:03 -06:00
if cmd . Config . Transformations != nil {
correlation . Config . Transformations = cmd . Config . Transformations
}
2022-08-03 08:18:51 -05:00
}
2022-10-10 08:36:14 -05:00
updateCount , err := session . Where ( "uid = ? AND source_uid = ?" , correlation . UID , correlation . SourceUID ) . Limit ( 1 ) . Update ( correlation )
if updateCount == 0 {
2022-08-03 08:18:51 -05:00
return ErrCorrelationNotFound
}
return err
} )
if err != nil {
return Correlation { } , err
}
return correlation , nil
}
2022-08-11 10:58:11 -05:00
func ( s CorrelationsService ) getCorrelation ( ctx context . Context , cmd GetCorrelationQuery ) ( Correlation , error ) {
correlation := Correlation {
UID : cmd . UID ,
SourceUID : cmd . SourceUID ,
}
2022-10-19 08:02:15 -05:00
err := s . SQLStore . WithTransactionalDbSession ( ctx , func ( session * db . Session ) error {
2022-08-11 10:58:11 -05:00
query := & datasources . GetDataSourceQuery {
2023-02-02 10:22:43 -06:00
OrgID : cmd . OrgId ,
UID : cmd . SourceUID ,
2022-08-11 10:58:11 -05:00
}
2023-02-09 08:49:44 -06:00
if _ , err := s . DataSourceService . GetDataSource ( ctx , query ) ; err != nil {
2022-08-11 10:58:11 -05:00
return ErrSourceDataSourceDoesNotExists
}
2023-08-24 02:39:30 -05:00
// Correlations created before the fix #72498 may have org_id = 0, but it's deprecated and will be removed in #72325
found , err := session . Select ( "correlation.*" ) . Join ( "" , "data_source AS dss" , "correlation.source_uid = dss.uid and (correlation.org_id = 0 or dss.org_id = correlation.org_id) and dss.org_id = ?" , cmd . OrgId ) . Join ( "" , "data_source AS dst" , "correlation.target_uid = dst.uid and dst.org_id = ?" , cmd . OrgId ) . Where ( "correlation.uid = ? AND correlation.source_uid = ?" , correlation . UID , correlation . SourceUID ) . Get ( & correlation )
2022-08-11 10:58:11 -05:00
if ! found {
return ErrCorrelationNotFound
}
return err
} )
if err != nil {
return Correlation { } , err
}
return correlation , nil
}
2023-03-21 15:27:25 -05:00
func ( s CorrelationsService ) CountCorrelations ( ctx context . Context ) ( * quota . Map , error ) {
u := & quota . Map { }
var err error
count := int64 ( 0 )
err = s . SQLStore . WithDbSession ( ctx , func ( sess * db . Session ) error {
q := sess . Table ( "correlation" )
count , err = q . Count ( )
if err != nil {
return err
}
tag , err := quota . NewTag ( QuotaTargetSrv , QuotaTarget , quota . GlobalScope )
if err != nil {
return err
}
u . Set ( tag , count )
return nil
} )
if err != nil {
return nil , err
}
return u , err
}
2022-08-11 10:58:11 -05:00
func ( s CorrelationsService ) getCorrelationsBySourceUID ( ctx context . Context , cmd GetCorrelationsBySourceUIDQuery ) ( [ ] Correlation , error ) {
correlations := make ( [ ] Correlation , 0 )
2022-10-19 08:02:15 -05:00
err := s . SQLStore . WithTransactionalDbSession ( ctx , func ( session * db . Session ) error {
2022-08-11 10:58:11 -05:00
query := & datasources . GetDataSourceQuery {
2023-02-02 10:22:43 -06:00
OrgID : cmd . OrgId ,
UID : cmd . SourceUID ,
2022-08-11 10:58:11 -05:00
}
2023-02-09 08:49:44 -06:00
if _ , err := s . DataSourceService . GetDataSource ( ctx , query ) ; err != nil {
2022-08-11 10:58:11 -05:00
return ErrSourceDataSourceDoesNotExists
}
2023-08-24 02:39:30 -05:00
// Correlations created before the fix #72498 may have org_id = 0, but it's deprecated and will be removed in #72325
return session . Select ( "correlation.*" ) . Join ( "" , "data_source AS dss" , "correlation.source_uid = dss.uid and (correlation.org_id = 0 or dss.org_id = correlation.org_id) and dss.org_id = ?" , cmd . OrgId ) . Join ( "" , "data_source AS dst" , "correlation.target_uid = dst.uid and dst.org_id = ?" , cmd . OrgId ) . Where ( "correlation.source_uid = ?" , cmd . SourceUID ) . Find ( & correlations )
2022-08-11 10:58:11 -05:00
} )
if err != nil {
return [ ] Correlation { } , err
}
return correlations , nil
}
2023-07-05 09:37:17 -05:00
func ( s CorrelationsService ) getCorrelations ( ctx context . Context , cmd GetCorrelationsQuery ) ( GetCorrelationsResponseBody , error ) {
result := GetCorrelationsResponseBody {
Correlations : make ( [ ] Correlation , 0 ) ,
Page : cmd . Page ,
Limit : cmd . Limit ,
}
2022-08-11 10:58:11 -05:00
2022-10-19 08:02:15 -05:00
err := s . SQLStore . WithDbSession ( ctx , func ( session * db . Session ) error {
2023-07-05 09:37:17 -05:00
offset := cmd . Limit * ( cmd . Page - 1 )
2023-08-24 02:39:30 -05:00
// Correlations created before the fix #72498 may have org_id = 0, but it's deprecated and will be removed in #72325
q := session . Select ( "correlation.*" ) . Join ( "" , "data_source AS dss" , "correlation.source_uid = dss.uid and (correlation.org_id = 0 or dss.org_id = correlation.org_id) and dss.org_id = ? " , cmd . OrgId ) . Join ( "" , "data_source AS dst" , "correlation.target_uid = dst.uid and dst.org_id = ?" , cmd . OrgId )
2023-07-05 09:37:17 -05:00
if len ( cmd . SourceUIDs ) > 0 {
q . In ( "dss.uid" , cmd . SourceUIDs )
}
return q . Limit ( int ( cmd . Limit ) , int ( offset ) ) . Find ( & result . Correlations )
2022-08-11 10:58:11 -05:00
} )
if err != nil {
2023-07-05 09:37:17 -05:00
return GetCorrelationsResponseBody { } , err
2022-08-11 10:58:11 -05:00
}
2023-07-05 09:37:17 -05:00
count , err := s . CountCorrelations ( ctx )
if err != nil {
return GetCorrelationsResponseBody { } , err
}
tag , err := quota . NewTag ( QuotaTargetSrv , QuotaTarget , quota . GlobalScope )
if err != nil {
return GetCorrelationsResponseBody { } , err
}
totalCount , _ := count . Get ( tag )
result . TotalCount = totalCount
return result , nil
2022-08-11 10:58:11 -05:00
}
2022-07-25 09:19:07 -05:00
func ( s CorrelationsService ) deleteCorrelationsBySourceUID ( ctx context . Context , cmd DeleteCorrelationsBySourceUIDCommand ) error {
2022-10-19 08:02:15 -05:00
return s . SQLStore . WithDbSession ( ctx , func ( session * db . Session ) error {
2023-08-24 02:39:30 -05:00
// Correlations created before the fix #72498 may have org_id = 0, but it's deprecated and will be removed in #72325
2023-09-13 08:10:09 -05:00
db := session . Where ( "source_uid = ? and (org_id = ? or org_id = 0)" , cmd . SourceUID , cmd . OrgId )
if cmd . OnlyProvisioned {
// bool in a struct needs to be in Where
// https://github.com/go-xorm/xorm/blob/v0.7.9/engine_cond.go#L102
db = db . And ( "provisioned = ?" , true )
}
_ , err := db . Delete ( & Correlation { } )
2022-07-25 09:19:07 -05:00
return err
} )
}
func ( s CorrelationsService ) deleteCorrelationsByTargetUID ( ctx context . Context , cmd DeleteCorrelationsByTargetUIDCommand ) error {
2022-10-19 08:02:15 -05:00
return s . SQLStore . WithDbSession ( ctx , func ( session * db . Session ) error {
2023-08-24 02:39:30 -05:00
// Correlations created before the fix #72498 may have org_id = 0, but it's deprecated and will be removed in #72325
_ , err := session . Where ( "source_uid = ? and (org_id = ? or org_id = 0)" , cmd . TargetUID , cmd . OrgId ) . Delete ( & Correlation { } )
2022-07-25 09:19:07 -05:00
return err
} )
}
2023-09-13 08:10:09 -05:00
// internal use: It's require only for correct migration of existing records. Can be removed in Grafana 11.
func ( s CorrelationsService ) createOrUpdateCorrelation ( ctx context . Context , cmd CreateCorrelationCommand ) error {
correlation := Correlation {
SourceUID : cmd . SourceUID ,
OrgID : cmd . OrgId ,
TargetUID : cmd . TargetUID ,
Label : cmd . Label ,
Description : cmd . Description ,
Config : cmd . Config ,
Provisioned : false ,
}
found := false
err := s . SQLStore . WithDbSession ( ctx , func ( session * db . Session ) error {
has , err := session . Get ( & correlation )
found = has
return err
} )
if err != nil {
return err
}
if found && cmd . Provisioned {
correlation . Provisioned = true
return s . SQLStore . WithDbSession ( ctx , func ( session * db . Session ) error {
_ , err := session . ID ( core . NewPK ( correlation . UID , correlation . SourceUID , correlation . OrgID ) ) . Cols ( "provisioned" ) . Update ( & correlation )
return err
} )
} else {
_ , err := s . createCorrelation ( ctx , cmd )
return err
}
}