Add apiVersion to plugin models (#87510)

This commit is contained in:
Andres Martinez Gotor
2024-05-14 13:58:27 +02:00
committed by GitHub
parent 2f11cf84e8
commit d8904f3ca4
21 changed files with 202 additions and 17 deletions
+1
View File
@@ -17,4 +17,5 @@ var (
ErrDatasourceIsReadOnly = errors.New("data source is readonly, can only be updated from configuration")
ErrDataSourceNameInvalid = errutil.ValidationFailed("datasource.nameInvalid", errutil.WithPublicMessage("Invalid datasource name."))
ErrDataSourceURLInvalid = errutil.ValidationFailed("datasource.urlInvalid", errutil.WithPublicMessage("Invalid datasource url."))
ErrDataSourceAPIVersionInvalid = errutil.ValidationFailed("datasource.apiVersionInvalid", errutil.WithPublicMessage("Invalid datasource apiVersion."))
)
+6
View File
@@ -63,6 +63,8 @@ type DataSource struct {
ReadOnly bool `json:"readOnly"`
UID string `json:"uid" xorm:"uid"`
// swagger:ignore
APIVersion string `json:"apiVersion" xorm:"api_version"`
// swagger:ignore
IsPrunable bool `xorm:"is_prunable"`
Created time.Time `json:"created,omitempty"`
@@ -164,6 +166,8 @@ type AddDataSourceCommand struct {
SecureJsonData map[string]string `json:"secureJsonData"`
UID string `json:"uid"`
// swagger:ignore
APIVersion string `json:"apiVersion"`
// swagger:ignore
IsPrunable bool
OrgID int64 `json:"-"`
@@ -190,6 +194,8 @@ type UpdateDataSourceCommand struct {
Version int `json:"version"`
UID string `json:"uid"`
// swagger:ignore
APIVersion string `json:"apiVersion"`
// swagger:ignore
IsPrunable bool
OrgID int64 `json:"-"`
+17 -3
View File
@@ -205,7 +205,7 @@ func (s *Service) AddDataSource(ctx context.Context, cmd *datasources.AddDataSou
cmd.Name = getAvailableName(cmd.Type, dataSources)
}
if err := validateFields(cmd.Name, cmd.URL); err != nil {
if err := s.validateFields(ctx, cmd.Name, cmd.URL, cmd.Type, cmd.APIVersion); err != nil {
return nil, err
}
@@ -287,7 +287,7 @@ func (s *Service) DeleteDataSource(ctx context.Context, cmd *datasources.DeleteD
func (s *Service) UpdateDataSource(ctx context.Context, cmd *datasources.UpdateDataSourceCommand) (*datasources.DataSource, error) {
var dataSource *datasources.DataSource
if err := validateFields(cmd.Name, cmd.URL); err != nil {
if err := s.validateFields(ctx, cmd.Name, cmd.URL, cmd.Type, cmd.APIVersion); err != nil {
return dataSource, err
}
@@ -716,7 +716,7 @@ func (s *Service) fillWithSecureJSONData(ctx context.Context, cmd *datasources.U
return nil
}
func validateFields(name, url string) error {
func (s *Service) validateFields(ctx context.Context, name, url, pluginID, apiVersion string) error {
if len(name) > maxDatasourceNameLen {
return datasources.ErrDataSourceNameInvalid.Errorf("max length is %d", maxDatasourceNameLen)
}
@@ -725,6 +725,20 @@ func validateFields(name, url string) error {
return datasources.ErrDataSourceURLInvalid.Errorf("max length is %d", maxDatasourceUrlLen)
}
if apiVersion == "" {
return nil
}
p, found := s.pluginStore.Plugin(context.Background(), pluginID)
if !found {
// Plugin not installed, ignore apiVersion check
return nil
}
if p.APIVersion != "" && p.APIVersion != apiVersion {
return datasources.ErrDataSourceAPIVersionInvalid.Errorf("expected %s, got %s", p.APIVersion, apiVersion)
}
return nil
}
@@ -19,6 +19,7 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
@@ -63,7 +64,14 @@ func TestService_AddDataSource(t *testing.T) {
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
quotaService := quotatest.New(false, nil)
mockPermission := acmock.NewMockedPermissionsService()
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), actest.FakeAccessControl{}, mockPermission, quotaService, &pluginstore.FakePluginStore{})
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), actest.FakeAccessControl{}, mockPermission, quotaService, &pluginstore.FakePluginStore{
PluginList: []pluginstore.Plugin{{
JSONData: plugins.JSONData{
Name: "test",
APIVersion: "v0alpha1",
},
}},
})
require.NoError(t, err)
cmd := &datasources.AddDataSourceCommand{
@@ -81,6 +89,15 @@ func TestService_AddDataSource(t *testing.T) {
_, err = dsService.AddDataSource(context.Background(), cmd)
require.EqualError(t, err, "[datasource.urlInvalid] max length is 255")
cmd = &datasources.AddDataSourceCommand{
OrgID: 1,
Name: "test",
APIVersion: "v0alpha2",
}
_, err = dsService.AddDataSource(context.Background(), cmd)
require.EqualError(t, err, "[datasource.apiVersionInvalid] expected v0alpha1, got v0alpha2")
})
}
@@ -284,6 +284,7 @@ func (ss *SqlStore) AddDataSource(ctx context.Context, cmd *datasources.AddDataS
ReadOnly: cmd.ReadOnly,
UID: cmd.UID,
IsPrunable: cmd.IsPrunable,
APIVersion: cmd.APIVersion,
}
if _, err := sess.Insert(ds); err != nil {
@@ -361,6 +362,7 @@ func (ss *SqlStore) UpdateDataSource(ctx context.Context, cmd *datasources.Updat
Version: cmd.Version + 1,
UID: cmd.UID,
IsPrunable: cmd.IsPrunable,
APIVersion: cmd.APIVersion,
}
sess.UseBool("is_default")
@@ -378,6 +380,7 @@ func (ss *SqlStore) UpdateDataSource(ctx context.Context, cmd *datasources.Updat
// Make sure secure json data is zeroed out if empty. We do this as we want to migrate secrets from
// secure json data to the unified secrets table.
sess.MustCols("secure_json_data")
sess.MustCols("api_version")
var updateSession *xorm.Session
if cmd.Version != 0 {
+12 -8
View File
@@ -56,13 +56,14 @@ func TestIntegrationDataAccess(t *testing.T) {
db := db.InitTestDB(t)
ss := SqlStore{db: db}
_, err := ss.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{
OrgID: 10,
Name: "laban",
Type: datasources.DS_GRAPHITE,
Access: datasources.DS_ACCESS_DIRECT,
URL: "http://test",
Database: "site",
ReadOnly: true,
OrgID: 10,
Name: "laban",
Type: datasources.DS_GRAPHITE,
Access: datasources.DS_ACCESS_DIRECT,
URL: "http://test",
Database: "site",
ReadOnly: true,
APIVersion: "v0alpha1",
})
require.NoError(t, err)
@@ -76,6 +77,7 @@ func TestIntegrationDataAccess(t *testing.T) {
require.EqualValues(t, 10, ds.OrgID)
require.Equal(t, "site", ds.Database)
require.True(t, ds.ReadOnly)
require.Equal(t, "v0alpha1", ds.APIVersion)
})
t.Run("generates uid if not specified", func(t *testing.T) {
@@ -146,9 +148,11 @@ func TestIntegrationDataAccess(t *testing.T) {
cmd := defaultUpdateDatasourceCommand
cmd.ID = ds.ID
cmd.Version = ds.Version
cmd.APIVersion = "v0alpha1"
ss := SqlStore{db: db}
_, err := ss.UpdateDataSource(context.Background(), &cmd)
ds, err := ss.UpdateDataSource(context.Background(), &cmd)
require.NoError(t, err)
require.Equal(t, "v0alpha1", ds.APIVersion)
})
t.Run("does not overwrite UID if not specified", func(t *testing.T) {