Add apiVersion to plugin models (#87510)
This commit is contained in:
@@ -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."))
|
||||
)
|
||||
|
||||
@@ -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:"-"`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user