mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Glue: Correlations minor APIs behavior improvements (#56078)
* add correlation config type, CorrelationConfig validator & default values * make config required when creating correlations * make targetUID optional, add validation for createCommand & configType * fix tests * update remaining tests * fix lint error * Update pkg/services/correlations/models.go Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * update docs Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
This commit is contained in:
@@ -34,11 +34,13 @@ func (s CorrelationsService) createCorrelation(ctx context.Context, cmd CreateCo
|
||||
return ErrSourceDataSourceReadOnly
|
||||
}
|
||||
|
||||
if err = s.DataSourceService.GetDataSource(ctx, &datasources.GetDataSourceQuery{
|
||||
OrgId: cmd.OrgId,
|
||||
Uid: cmd.TargetUID,
|
||||
}); err != nil {
|
||||
return ErrTargetDataSourceDoesNotExists
|
||||
if cmd.TargetUID != nil {
|
||||
if err = s.DataSourceService.GetDataSource(ctx, &datasources.GetDataSourceQuery{
|
||||
OrgId: cmd.OrgId,
|
||||
Uid: *cmd.TargetUID,
|
||||
}); err != nil {
|
||||
return ErrTargetDataSourceDoesNotExists
|
||||
}
|
||||
}
|
||||
|
||||
_, err = session.Insert(correlation)
|
||||
@@ -206,7 +208,7 @@ func (s CorrelationsService) deleteCorrelationsBySourceUID(ctx context.Context,
|
||||
|
||||
func (s CorrelationsService) deleteCorrelationsByTargetUID(ctx context.Context, cmd DeleteCorrelationsByTargetUIDCommand) error {
|
||||
return s.SQLStore.WithDbSession(ctx, func(session *sqlstore.DBSession) error {
|
||||
_, err := session.Delete(&Correlation{TargetUID: cmd.TargetUID})
|
||||
_, err := session.Delete(&Correlation{TargetUID: &cmd.TargetUID})
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
package correlations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -11,20 +13,49 @@ var (
|
||||
ErrCorrelationFailedGenerateUniqueUid = errors.New("failed to generate unique correlation UID")
|
||||
ErrCorrelationNotFound = errors.New("correlation not found")
|
||||
ErrUpdateCorrelationEmptyParams = errors.New("not enough parameters to edit correlation")
|
||||
ErrInvalidConfigType = errors.New("invalid correlation config type")
|
||||
)
|
||||
|
||||
// CorrelationConfigTarget is the target data query specific to target data source (Correlation.TargetUID)
|
||||
// swagger:model
|
||||
type CorrelationConfigTarget interface{}
|
||||
type CorrelationConfigType string
|
||||
|
||||
const (
|
||||
ConfigTypeQuery CorrelationConfigType = "query"
|
||||
)
|
||||
|
||||
func (t CorrelationConfigType) Validate() error {
|
||||
if t != ConfigTypeQuery {
|
||||
return fmt.Errorf("%s: \"%s\"", ErrInvalidConfigType, t)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
type CorrelationConfig struct {
|
||||
// Field used to attach the correlation link
|
||||
// required:true
|
||||
Field string `json:"field"`
|
||||
Field string `json:"field" binding:"Required"`
|
||||
// Target type
|
||||
// required:true
|
||||
Type CorrelationConfigType `json:"type" binding:"Required"`
|
||||
// Target data query
|
||||
// required:true
|
||||
Target CorrelationConfigTarget `json:"target"`
|
||||
Target map[string]interface{} `json:"target" binding:"Required"`
|
||||
}
|
||||
|
||||
func (c CorrelationConfig) MarshalJSON() ([]byte, error) {
|
||||
target := c.Target
|
||||
if target == nil {
|
||||
target = map[string]interface{}{}
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
Type CorrelationConfigType `json:"type"`
|
||||
Field string `json:"field"`
|
||||
Target map[string]interface{} `json:"target"`
|
||||
}{
|
||||
Type: ConfigTypeQuery,
|
||||
Field: c.Field,
|
||||
Target: target,
|
||||
})
|
||||
}
|
||||
|
||||
// Correlation is the model for correlations definitions
|
||||
@@ -38,7 +69,7 @@ type Correlation struct {
|
||||
SourceUID string `json:"sourceUID" xorm:"pk 'source_uid'"`
|
||||
// UID of the data source the correlation points to
|
||||
// example:PE1C5CBDA0504A6A3
|
||||
TargetUID string `json:"targetUID" xorm:"target_uid"`
|
||||
TargetUID *string `json:"targetUID" xorm:"target_uid"`
|
||||
// Label identifying the correlation
|
||||
// example: My Label
|
||||
Label string `json:"label" xorm:"label"`
|
||||
@@ -67,7 +98,7 @@ type CreateCorrelationCommand struct {
|
||||
SkipReadOnlyCheck bool `json:"-"`
|
||||
// Target data source UID to which the correlation is created
|
||||
// example:PE1C5CBDA0504A6A3
|
||||
TargetUID string `json:"targetUID" binding:"Required"`
|
||||
TargetUID *string `json:"targetUID"`
|
||||
// Optional label identifying the correlation
|
||||
// example: My label
|
||||
Label string `json:"label"`
|
||||
@@ -76,7 +107,17 @@ type CreateCorrelationCommand struct {
|
||||
Description string `json:"description"`
|
||||
// Arbitrary configuration object handled in frontend
|
||||
// example: { field: "job", target: { query: "job=app" } }
|
||||
Config CorrelationConfig `json:"config"`
|
||||
Config CorrelationConfig `json:"config" binding:"Required"`
|
||||
}
|
||||
|
||||
func (c CreateCorrelationCommand) Validate() error {
|
||||
if err := c.Config.Type.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.TargetUID == nil && c.Config.Type == ConfigTypeQuery {
|
||||
return fmt.Errorf("correlations of type \"%s\" must have a targetUID", ConfigTypeQuery)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
|
91
pkg/services/correlations/models_test.go
Normal file
91
pkg/services/correlations/models_test.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package correlations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCorrelationModels(t *testing.T) {
|
||||
t.Run("CreateCorrelationCommand Validate", func(t *testing.T) {
|
||||
t.Run("Successfully validates a correct create command", func(t *testing.T) {
|
||||
targetUid := "targetUid"
|
||||
config := &CorrelationConfig{
|
||||
Field: "field",
|
||||
Target: map[string]interface{}{},
|
||||
Type: ConfigTypeQuery,
|
||||
}
|
||||
cmd := &CreateCorrelationCommand{
|
||||
SourceUID: "some-uid",
|
||||
OrgId: 1,
|
||||
TargetUID: &targetUid,
|
||||
Config: *config,
|
||||
}
|
||||
|
||||
require.NoError(t, cmd.Validate())
|
||||
})
|
||||
|
||||
t.Run("Fails if target UID is not set and config type = query", func(t *testing.T) {
|
||||
config := &CorrelationConfig{
|
||||
Field: "field",
|
||||
Target: map[string]interface{}{},
|
||||
Type: ConfigTypeQuery,
|
||||
}
|
||||
cmd := &CreateCorrelationCommand{
|
||||
SourceUID: "some-uid",
|
||||
OrgId: 1,
|
||||
Config: *config,
|
||||
}
|
||||
|
||||
require.Error(t, cmd.Validate())
|
||||
})
|
||||
|
||||
t.Run("Fails if config type is unknown", func(t *testing.T) {
|
||||
config := &CorrelationConfig{
|
||||
Field: "field",
|
||||
Target: map[string]interface{}{},
|
||||
Type: "unknown config type",
|
||||
}
|
||||
cmd := &CreateCorrelationCommand{
|
||||
SourceUID: "some-uid",
|
||||
OrgId: 1,
|
||||
Config: *config,
|
||||
}
|
||||
|
||||
require.Error(t, cmd.Validate())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("CorrelationConfigType Validate", func(t *testing.T) {
|
||||
t.Run("Successfully validates a correct type", func(t *testing.T) {
|
||||
type test struct {
|
||||
input CorrelationConfigType
|
||||
assertion require.ErrorAssertionFunc
|
||||
}
|
||||
|
||||
tests := []test{
|
||||
{input: "query", assertion: require.NoError},
|
||||
{input: "link", assertion: require.Error},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc.assertion(t, tc.input.Validate())
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("CorrelationConfig JSON Marshaling", func(t *testing.T) {
|
||||
t.Run("Applies a default empty object if target is not defined", func(t *testing.T) {
|
||||
config := CorrelationConfig{
|
||||
Field: "field",
|
||||
Type: ConfigTypeQuery,
|
||||
}
|
||||
|
||||
data, err := json.Marshal(config)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, `{"type":"query","field":"field","target":{}}`, string(data))
|
||||
})
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user