Use org service instead of sqlstore (#56407)

* Use org service instead of sqlstore

* Remove methods from sqlstore

* Remove commented out code

* Fix lint

* Fix lint 2
This commit is contained in:
idafurjes 2022-10-13 14:40:46 +02:00 committed by GitHub
parent b0cb02568a
commit ef651daed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 164 additions and 267 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
@ -438,9 +439,8 @@ func TestIntegrationStore_GetResourcePermissions(t *testing.T) {
func seedResourcePermissions(t *testing.T, store *store, sql *sqlstore.SQLStore, actions []string, resource, resourceID, resourceAttribute string, numUsers int) { func seedResourcePermissions(t *testing.T, store *store, sql *sqlstore.SQLStore, actions []string, resource, resourceID, resourceAttribute string, numUsers int) {
t.Helper() t.Helper()
var org *models.Org
for i := 0; i < numUsers; i++ { for i := 0; i < numUsers; i++ {
org, _ := sql.GetOrgByName("test")
if org == nil { if org == nil {
addedOrg, err := sql.CreateOrgWithMember("test", int64(i)) addedOrg, err := sql.CreateOrgWithMember("test", int64(i))
require.NoError(t, err) require.NoError(t, err)

View File

@ -170,6 +170,63 @@ func TestIntegrationOrgDataAccess(t *testing.T) {
assert.Equal(t, int64(1), result.ID) assert.Equal(t, int64(1), result.ID)
}) })
}) })
t.Run("Testing Account DB Access", func(t *testing.T) {
sqlStore := sqlstore.InitTestDB(t)
t.Run("Given we have organizations, we can query them by IDs", func(t *testing.T) {
var err error
var cmd *models.CreateOrgCommand
ids := []int64{}
for i := 1; i < 4; i++ {
cmd = &models.CreateOrgCommand{Name: fmt.Sprint("Org #", i)}
err = sqlStore.CreateOrg(context.Background(), cmd)
require.NoError(t, err)
ids = append(ids, cmd.Result.Id)
}
query := &org.SearchOrgsQuery{IDs: ids}
queryResult, err := orgStore.Search(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(queryResult), 3)
})
t.Run("Given we have organizations, we can limit and paginate search", func(t *testing.T) {
sqlStore = sqlstore.InitTestDB(t)
for i := 1; i < 4; i++ {
cmd := &models.CreateOrgCommand{Name: fmt.Sprint("Org #", i)}
err := sqlStore.CreateOrg(context.Background(), cmd)
require.NoError(t, err)
}
t.Run("Should be able to search with defaults", func(t *testing.T) {
query := &org.SearchOrgsQuery{}
queryResult, err := orgStore.Search(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(queryResult), 3)
})
t.Run("Should be able to limit search", func(t *testing.T) {
query := &org.SearchOrgsQuery{Limit: 1}
queryResult, err := orgStore.Search(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(queryResult), 1)
})
t.Run("Should be able to limit and paginate search", func(t *testing.T) {
query := &org.SearchOrgsQuery{Limit: 2, Page: 1}
queryResult, err := orgStore.Search(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(queryResult), 1)
})
})
})
} }
func TestIntegrationOrgUserDataAccess(t *testing.T) { func TestIntegrationOrgUserDataAccess(t *testing.T) {

View File

@ -9,6 +9,7 @@ import (
"strings" "strings"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/provisioning/utils" "github.com/grafana/grafana/pkg/services/provisioning/utils"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@ -16,7 +17,7 @@ import (
type configReader struct { type configReader struct {
path string path string
log log.Logger log log.Logger
orgStore utils.OrgStore orgService org.Service
} }
func (cr *configReader) parseConfigs(file fs.DirEntry) ([]*config, error) { func (cr *configReader) parseConfigs(file fs.DirEntry) ([]*config, error) {
@ -94,7 +95,7 @@ func (cr *configReader) readConfig(ctx context.Context) ([]*config, error) {
dashboard.OrgID = 1 dashboard.OrgID = 1
} }
if err := utils.CheckOrgExists(ctx, cr.orgStore, dashboard.OrgID); err != nil { if err := utils.CheckOrgExists(ctx, cr.orgService, dashboard.OrgID); err != nil {
return nil, fmt.Errorf("failed to provision dashboards with %q reader: %w", dashboard.Name, err) return nil, fmt.Errorf("failed to provision dashboards with %q reader: %w", dashboard.Name, err)
} }

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org/orgtest"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
) )
@ -26,12 +27,15 @@ func TestDashboardsAsConfig(t *testing.T) {
t.Run("Dashboards as configuration", func(t *testing.T) { t.Run("Dashboards as configuration", func(t *testing.T) {
logger := log.New("test-logger") logger := log.New("test-logger")
store := sqlstore.InitTestDB(t) store := sqlstore.InitTestDB(t)
orgFake := orgtest.NewOrgServiceFake()
t.Run("Should fail if orgs don't exist in the database", func(t *testing.T) { t.Run("Should fail if orgs don't exist in the database", func(t *testing.T) {
cfgProvider := configReader{path: appliedDefaults, log: logger, orgStore: store} orgFake.ExpectedError = models.ErrOrgNotFound
cfgProvider := configReader{path: appliedDefaults, log: logger, orgService: orgFake}
_, err := cfgProvider.readConfig(context.Background()) _, err := cfgProvider.readConfig(context.Background())
require.Error(t, err) require.Error(t, err)
assert.True(t, errors.Is(err, models.ErrOrgNotFound)) assert.True(t, errors.Is(err, models.ErrOrgNotFound))
orgFake.ExpectedError = nil
}) })
for i := 1; i <= 2; i++ { for i := 1; i <= 2; i++ {
@ -41,7 +45,7 @@ func TestDashboardsAsConfig(t *testing.T) {
} }
t.Run("default values should be applied", func(t *testing.T) { t.Run("default values should be applied", func(t *testing.T) {
cfgProvider := configReader{path: appliedDefaults, log: logger, orgStore: store} cfgProvider := configReader{path: appliedDefaults, log: logger, orgService: orgFake}
cfg, err := cfgProvider.readConfig(context.Background()) cfg, err := cfgProvider.readConfig(context.Background())
require.NoError(t, err) require.NoError(t, err)
@ -52,7 +56,7 @@ func TestDashboardsAsConfig(t *testing.T) {
t.Run("Can read config file version 1 format", func(t *testing.T) { t.Run("Can read config file version 1 format", func(t *testing.T) {
_ = os.Setenv("TEST_VAR", "general") _ = os.Setenv("TEST_VAR", "general")
cfgProvider := configReader{path: simpleDashboardConfig, log: logger, orgStore: store} cfgProvider := configReader{path: simpleDashboardConfig, log: logger, orgService: orgFake}
cfg, err := cfgProvider.readConfig(context.Background()) cfg, err := cfgProvider.readConfig(context.Background())
_ = os.Unsetenv("TEST_VAR") _ = os.Unsetenv("TEST_VAR")
require.NoError(t, err) require.NoError(t, err)
@ -61,7 +65,7 @@ func TestDashboardsAsConfig(t *testing.T) {
}) })
t.Run("Can read config file in version 0 format", func(t *testing.T) { t.Run("Can read config file in version 0 format", func(t *testing.T) {
cfgProvider := configReader{path: oldVersion, log: logger, orgStore: store} cfgProvider := configReader{path: oldVersion, log: logger, orgService: orgFake}
cfg, err := cfgProvider.readConfig(context.Background()) cfg, err := cfgProvider.readConfig(context.Background())
require.NoError(t, err) require.NoError(t, err)
@ -69,7 +73,7 @@ func TestDashboardsAsConfig(t *testing.T) {
}) })
t.Run("Should skip invalid path", func(t *testing.T) { t.Run("Should skip invalid path", func(t *testing.T) {
cfgProvider := configReader{path: "/invalid-directory", log: logger, orgStore: store} cfgProvider := configReader{path: "/invalid-directory", log: logger, orgService: orgFake}
cfg, err := cfgProvider.readConfig(context.Background()) cfg, err := cfgProvider.readConfig(context.Background())
if err != nil { if err != nil {
t.Fatalf("readConfig return an error %v", err) t.Fatalf("readConfig return an error %v", err)
@ -79,7 +83,7 @@ func TestDashboardsAsConfig(t *testing.T) {
}) })
t.Run("Should skip broken config files", func(t *testing.T) { t.Run("Should skip broken config files", func(t *testing.T) {
cfgProvider := configReader{path: brokenConfigs, log: logger, orgStore: store} cfgProvider := configReader{path: brokenConfigs, log: logger, orgService: orgFake}
cfg, err := cfgProvider.readConfig(context.Background()) cfg, err := cfgProvider.readConfig(context.Background())
if err != nil { if err != nil {
t.Fatalf("readConfig return an error %v", err) t.Fatalf("readConfig return an error %v", err)

View File

@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/provisioning/utils" "github.com/grafana/grafana/pkg/services/provisioning/utils"
) )
@ -23,7 +24,7 @@ type DashboardProvisioner interface {
} }
// DashboardProvisionerFactory creates DashboardProvisioners based on input // DashboardProvisionerFactory creates DashboardProvisioners based on input
type DashboardProvisionerFactory func(context.Context, string, dashboards.DashboardProvisioningService, utils.OrgStore, utils.DashboardStore) (DashboardProvisioner, error) type DashboardProvisionerFactory func(context.Context, string, dashboards.DashboardProvisioningService, org.Service, utils.DashboardStore) (DashboardProvisioner, error)
// Provisioner is responsible for syncing dashboard from disk to Grafana's database. // Provisioner is responsible for syncing dashboard from disk to Grafana's database.
type Provisioner struct { type Provisioner struct {
@ -39,9 +40,9 @@ func (provider *Provisioner) HasDashboardSources() bool {
} }
// New returns a new DashboardProvisioner // New returns a new DashboardProvisioner
func New(ctx context.Context, configDirectory string, provisioner dashboards.DashboardProvisioningService, orgStore utils.OrgStore, dashboardStore utils.DashboardStore) (DashboardProvisioner, error) { func New(ctx context.Context, configDirectory string, provisioner dashboards.DashboardProvisioningService, orgService org.Service, dashboardStore utils.DashboardStore) (DashboardProvisioner, error) {
logger := log.New("provisioning.dashboard") logger := log.New("provisioning.dashboard")
cfgReader := &configReader{path: configDirectory, log: logger, orgStore: orgStore} cfgReader := &configReader{path: configDirectory, log: logger, orgService: orgService}
configs, err := cfgReader.readConfig(ctx) configs, err := cfgReader.readConfig(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("%v: %w", "Failed to read dashboards config", err) return nil, fmt.Errorf("%v: %w", "Failed to read dashboards config", err)

View File

@ -12,12 +12,13 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/provisioning/utils" "github.com/grafana/grafana/pkg/services/provisioning/utils"
) )
type configReader struct { type configReader struct {
log log.Logger log log.Logger
orgStore utils.OrgStore orgService org.Service
} }
func (cr *configReader) readConfig(ctx context.Context, path string) ([]*configs, error) { func (cr *configReader) readConfig(ctx context.Context, path string) ([]*configs, error) {
@ -130,7 +131,7 @@ func (cr *configReader) validateDefaultUniqueness(ctx context.Context, datasourc
} }
func (cr *configReader) validateAccessAndOrgID(ctx context.Context, ds *upsertDataSourceFromConfig) error { func (cr *configReader) validateAccessAndOrgID(ctx context.Context, ds *upsertDataSourceFromConfig) error {
if err := utils.CheckOrgExists(ctx, cr.orgStore, ds.OrgID); err != nil { if err := utils.CheckOrgExists(ctx, cr.orgService, ds.OrgID); err != nil {
return err return err
} }

View File

@ -8,9 +8,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/correlations" "github.com/grafana/grafana/pkg/services/correlations"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/org/orgtest"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@ -34,9 +35,9 @@ var (
func TestDatasourceAsConfig(t *testing.T) { func TestDatasourceAsConfig(t *testing.T) {
t.Run("when some values missing should apply default on insert", func(t *testing.T) { t.Run("when some values missing should apply default on insert", func(t *testing.T) {
store := &spyStore{} store := &spyStore{}
orgStore := &mockOrgStore{ExpectedOrg: &models.Org{Id: 1}} orgFake := &orgtest.FakeOrgService{ExpectedOrg: &org.Org{ID: 1}}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), withoutDefaults) err := dc.applyChanges(context.Background(), withoutDefaults)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -53,9 +54,9 @@ func TestDatasourceAsConfig(t *testing.T) {
store := &spyStore{ store := &spyStore{
items: []*datasources.DataSource{{Name: "My datasource name", OrgId: 1, Id: 1, Uid: util.GenerateShortUID()}}, items: []*datasources.DataSource{{Name: "My datasource name", OrgId: 1, Id: 1, Uid: util.GenerateShortUID()}},
} }
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), withoutDefaults) err := dc.applyChanges(context.Background(), withoutDefaults)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -69,9 +70,9 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("no datasource in database", func(t *testing.T) { t.Run("no datasource in database", func(t *testing.T) {
store := &spyStore{} store := &spyStore{}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig) err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -84,9 +85,9 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("One datasource in database with same name should update one datasource", func(t *testing.T) { t.Run("One datasource in database with same name should update one datasource", func(t *testing.T) {
store := &spyStore{items: []*datasources.DataSource{{Name: "Graphite", OrgId: 1, Id: 1}}} store := &spyStore{items: []*datasources.DataSource{{Name: "Graphite", OrgId: 1, Id: 1}}}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig) err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -99,18 +100,18 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("Two datasources with is_default should raise error", func(t *testing.T) { t.Run("Two datasources with is_default should raise error", func(t *testing.T) {
store := &spyStore{} store := &spyStore{}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), doubleDatasourcesConfig) err := dc.applyChanges(context.Background(), doubleDatasourcesConfig)
require.Equal(t, err, ErrInvalidConfigToManyDefault) require.Equal(t, err, ErrInvalidConfigToManyDefault)
}) })
t.Run("Multiple datasources in different organizations with isDefault in each organization should not raise error", func(t *testing.T) { t.Run("Multiple datasources in different organizations with isDefault in each organization should not raise error", func(t *testing.T) {
store := &spyStore{} store := &spyStore{}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), multipleOrgsWithDefault) err := dc.applyChanges(context.Background(), multipleOrgsWithDefault)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, len(store.inserted), 4) require.Equal(t, len(store.inserted), 4)
@ -122,9 +123,9 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("Remove one datasource should have removed old datasource", func(t *testing.T) { t.Run("Remove one datasource should have removed old datasource", func(t *testing.T) {
store := &spyStore{} store := &spyStore{}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), deleteOneDatasource) err := dc.applyChanges(context.Background(), deleteOneDatasource)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -139,9 +140,9 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("Two configured datasource and purge others", func(t *testing.T) { t.Run("Two configured datasource and purge others", func(t *testing.T) {
store := &spyStore{items: []*datasources.DataSource{{Name: "old-graphite", OrgId: 1, Id: 1}, {Name: "old-graphite2", OrgId: 1, Id: 2}}} store := &spyStore{items: []*datasources.DataSource{{Name: "old-graphite", OrgId: 1, Id: 1}, {Name: "old-graphite2", OrgId: 1, Id: 2}}}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), twoDatasourcesConfigPurgeOthers) err := dc.applyChanges(context.Background(), twoDatasourcesConfigPurgeOthers)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -154,9 +155,9 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("Two configured datasource and purge others = false", func(t *testing.T) { t.Run("Two configured datasource and purge others = false", func(t *testing.T) {
store := &spyStore{items: []*datasources.DataSource{{Name: "Graphite", OrgId: 1, Id: 1}, {Name: "old-graphite2", OrgId: 1, Id: 2}}} store := &spyStore{items: []*datasources.DataSource{{Name: "Graphite", OrgId: 1, Id: 1}, {Name: "old-graphite2", OrgId: 1, Id: 2}}}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig) err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -174,14 +175,14 @@ func TestDatasourceAsConfig(t *testing.T) {
}) })
t.Run("invalid access should warn about invalid value and return 'proxy'", func(t *testing.T) { t.Run("invalid access should warn about invalid value and return 'proxy'", func(t *testing.T) {
reader := &configReader{log: logger, orgStore: &mockOrgStore{}} reader := &configReader{log: logger, orgService: &orgtest.FakeOrgService{}}
configs, err := reader.readConfig(context.Background(), invalidAccess) configs, err := reader.readConfig(context.Background(), invalidAccess)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, configs[0].Datasources[0].Access, datasources.DS_ACCESS_PROXY) require.Equal(t, configs[0].Datasources[0].Access, datasources.DS_ACCESS_PROXY)
}) })
t.Run("skip invalid directory", func(t *testing.T) { t.Run("skip invalid directory", func(t *testing.T) {
cfgProvider := &configReader{log: log.New("test logger"), orgStore: &mockOrgStore{}} cfgProvider := &configReader{log: log.New("test logger"), orgService: &orgtest.FakeOrgService{}}
cfg, err := cfgProvider.readConfig(context.Background(), "./invalid-directory") cfg, err := cfgProvider.readConfig(context.Background(), "./invalid-directory")
if err != nil { if err != nil {
t.Fatalf("readConfig return an error %v", err) t.Fatalf("readConfig return an error %v", err)
@ -192,7 +193,7 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("can read all properties from version 1", func(t *testing.T) { t.Run("can read all properties from version 1", func(t *testing.T) {
_ = os.Setenv("TEST_VAR", "name") _ = os.Setenv("TEST_VAR", "name")
cfgProvider := &configReader{log: log.New("test logger"), orgStore: &mockOrgStore{}} cfgProvider := &configReader{log: log.New("test logger"), orgService: &orgtest.FakeOrgService{}}
cfg, err := cfgProvider.readConfig(context.Background(), allProperties) cfg, err := cfgProvider.readConfig(context.Background(), allProperties)
_ = os.Unsetenv("TEST_VAR") _ = os.Unsetenv("TEST_VAR")
if err != nil { if err != nil {
@ -221,7 +222,7 @@ func TestDatasourceAsConfig(t *testing.T) {
}) })
t.Run("can read all properties from version 0", func(t *testing.T) { t.Run("can read all properties from version 0", func(t *testing.T) {
cfgProvider := &configReader{log: log.New("test logger"), orgStore: &mockOrgStore{}} cfgProvider := &configReader{log: log.New("test logger"), orgService: &orgtest.FakeOrgService{}}
cfg, err := cfgProvider.readConfig(context.Background(), versionZero) cfg, err := cfgProvider.readConfig(context.Background(), versionZero)
if err != nil { if err != nil {
t.Fatalf("readConfig return an error %v", err) t.Fatalf("readConfig return an error %v", err)
@ -240,9 +241,9 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("Correlations", func(t *testing.T) { t.Run("Correlations", func(t *testing.T) {
t.Run("Creates two correlations", func(t *testing.T) { t.Run("Creates two correlations", func(t *testing.T) {
store := &spyStore{} store := &spyStore{}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), oneDatasourceWithTwoCorrelations) err := dc.applyChanges(context.Background(), oneDatasourceWithTwoCorrelations)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -255,9 +256,9 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("Updating existing datasource deletes existing correlations and creates two", func(t *testing.T) { t.Run("Updating existing datasource deletes existing correlations and creates two", func(t *testing.T) {
store := &spyStore{items: []*datasources.DataSource{{Name: "Graphite", OrgId: 1, Id: 1}}} store := &spyStore{items: []*datasources.DataSource{{Name: "Graphite", OrgId: 1, Id: 1}}}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
correlationsStore := &mockCorrelationsStore{} correlationsStore := &mockCorrelationsStore{}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), oneDatasourceWithTwoCorrelations) err := dc.applyChanges(context.Background(), oneDatasourceWithTwoCorrelations)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -270,10 +271,10 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Run("Deleting datasource deletes existing correlations", func(t *testing.T) { t.Run("Deleting datasource deletes existing correlations", func(t *testing.T) {
store := &spyStore{items: []*datasources.DataSource{{Name: "old-data-source", OrgId: 1, Id: 1, Uid: "some-uid"}}} store := &spyStore{items: []*datasources.DataSource{{Name: "old-data-source", OrgId: 1, Id: 1, Uid: "some-uid"}}}
orgStore := &mockOrgStore{} orgFake := &orgtest.FakeOrgService{}
targetUid := "target-uid" targetUid := "target-uid"
correlationsStore := &mockCorrelationsStore{items: []correlations.Correlation{{UID: "some-uid", SourceUID: "some-uid", TargetUID: &targetUid}}} correlationsStore := &mockCorrelationsStore{items: []correlations.Correlation{{UID: "some-uid", SourceUID: "some-uid", TargetUID: &targetUid}}}
dc := newDatasourceProvisioner(logger, store, correlationsStore, orgStore) dc := newDatasourceProvisioner(logger, store, correlationsStore, orgFake)
err := dc.applyChanges(context.Background(), deleteOneDatasource) err := dc.applyChanges(context.Background(), deleteOneDatasource)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -337,13 +338,6 @@ func validateDatasourceV1(t *testing.T, dsCfg *configs) {
}}, ds.Correlations) }}, ds.Correlations)
} }
type mockOrgStore struct{ ExpectedOrg *models.Org }
func (m *mockOrgStore) GetOrgById(c context.Context, cmd *models.GetOrgByIdQuery) error {
cmd.Result = m.ExpectedOrg
return nil
}
type mockCorrelationsStore struct { type mockCorrelationsStore struct {
created []correlations.CreateCorrelationCommand created []correlations.CreateCorrelationCommand
deletedBySourceUID []correlations.DeleteCorrelationsBySourceUIDCommand deletedBySourceUID []correlations.DeleteCorrelationsBySourceUIDCommand

View File

@ -10,7 +10,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/correlations" "github.com/grafana/grafana/pkg/services/correlations"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/provisioning/utils" "github.com/grafana/grafana/pkg/services/org"
) )
type Store interface { type Store interface {
@ -34,8 +34,8 @@ var (
// Provision scans a directory for provisioning config files // Provision scans a directory for provisioning config files
// and provisions the datasource in those files. // and provisions the datasource in those files.
func Provision(ctx context.Context, configDirectory string, store Store, correlationsStore CorrelationsStore, orgStore utils.OrgStore) error { func Provision(ctx context.Context, configDirectory string, store Store, correlationsStore CorrelationsStore, orgService org.Service) error {
dc := newDatasourceProvisioner(log.New("provisioning.datasources"), store, correlationsStore, orgStore) dc := newDatasourceProvisioner(log.New("provisioning.datasources"), store, correlationsStore, orgService)
return dc.applyChanges(ctx, configDirectory) return dc.applyChanges(ctx, configDirectory)
} }
@ -48,10 +48,10 @@ type DatasourceProvisioner struct {
correlationsStore CorrelationsStore correlationsStore CorrelationsStore
} }
func newDatasourceProvisioner(log log.Logger, store Store, correlationsStore CorrelationsStore, orgStore utils.OrgStore) DatasourceProvisioner { func newDatasourceProvisioner(log log.Logger, store Store, correlationsStore CorrelationsStore, orgService org.Service) DatasourceProvisioner {
return DatasourceProvisioner{ return DatasourceProvisioner{
log: log, log: log,
cfgProvider: &configReader{log: log, orgStore: orgStore}, cfgProvider: &configReader{log: log, orgService: orgService},
store: store, store: store,
correlationsStore: correlationsStore, correlationsStore: correlationsStore,
} }

View File

@ -24,14 +24,10 @@ type Manager interface {
GetAlertNotificationsWithUidToSend(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) error GetAlertNotificationsWithUidToSend(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) error
UpdateAlertNotificationWithUid(ctx context.Context, cmd *models.UpdateAlertNotificationWithUidCommand) error UpdateAlertNotificationWithUid(ctx context.Context, cmd *models.UpdateAlertNotificationWithUidCommand) error
} }
type SQLStore interface {
GetOrgById(c context.Context, cmd *models.GetOrgByIdQuery) error
GetOrgByNameHandler(ctx context.Context, query *models.GetOrgByNameQuery) error
}
// Provision alert notifiers // Provision alert notifiers
func Provision(ctx context.Context, configDirectory string, alertingService Manager, orgService org.Service, sqlstore SQLStore, encryptionService encryption.Internal, notificationService *notifications.NotificationService) error { func Provision(ctx context.Context, configDirectory string, alertingService Manager, orgService org.Service, encryptionService encryption.Internal, notificationService *notifications.NotificationService) error {
dc := newNotificationProvisioner(orgService, sqlstore, alertingService, encryptionService, notificationService, log.New("provisioning.notifiers")) dc := newNotificationProvisioner(orgService, alertingService, encryptionService, notificationService, log.New("provisioning.notifiers"))
return dc.applyChanges(ctx, configDirectory) return dc.applyChanges(ctx, configDirectory)
} }
@ -40,11 +36,10 @@ type NotificationProvisioner struct {
log log.Logger log log.Logger
cfgProvider *configReader cfgProvider *configReader
alertingManager Manager alertingManager Manager
sqlstore SQLStore
orgService org.Service orgService org.Service
} }
func newNotificationProvisioner(orgService org.Service, store SQLStore, alertingManager Manager, encryptionService encryption.Internal, notifiationService *notifications.NotificationService, log log.Logger) NotificationProvisioner { func newNotificationProvisioner(orgService org.Service, alertingManager Manager, encryptionService encryption.Internal, notifiationService *notifications.NotificationService, log log.Logger) NotificationProvisioner {
return NotificationProvisioner{ return NotificationProvisioner{
log: log, log: log,
alertingManager: alertingManager, alertingManager: alertingManager,
@ -52,9 +47,8 @@ func newNotificationProvisioner(orgService org.Service, store SQLStore, alerting
encryptionService: encryptionService, encryptionService: encryptionService,
notificationService: notifiationService, notificationService: notifiationService,
log: log, log: log,
orgStore: store, orgService: orgService,
}, },
sqlstore: store,
orgService: orgService, orgService: orgService,
} }
} }

View File

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption" "github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/provisioning/utils" "github.com/grafana/grafana/pkg/services/provisioning/utils"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@ -21,7 +22,7 @@ import (
type configReader struct { type configReader struct {
encryptionService encryption.Internal encryptionService encryption.Internal
notificationService *notifications.NotificationService notificationService *notifications.NotificationService
orgStore utils.OrgStore orgService org.Service
log log.Logger log log.Logger
} }
@ -94,7 +95,7 @@ func (cr *configReader) checkOrgIDAndOrgName(ctx context.Context, notifications
notification.OrgID = 0 notification.OrgID = 0
} }
} else { } else {
if err := utils.CheckOrgExists(ctx, cr.orgStore, notification.OrgID); err != nil { if err := utils.CheckOrgExists(ctx, cr.orgService, notification.OrgID); err != nil {
return fmt.Errorf("failed to provision %q notification: %w", notification.Name, err) return fmt.Errorf("failed to provision %q notification: %w", notification.Name, err)
} }
} }

View File

@ -34,6 +34,7 @@ var (
func TestNotificationAsConfig(t *testing.T) { func TestNotificationAsConfig(t *testing.T) {
var sqlStore *sqlstore.SQLStore var sqlStore *sqlstore.SQLStore
var orgFake org.Service
var ns *alerting.AlertNotificationService var ns *alerting.AlertNotificationService
logger := log.New("fake.log") logger := log.New("fake.log")
orgService := orgtest.NewOrgServiceFake() orgService := orgtest.NewOrgServiceFake()
@ -44,6 +45,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Testing notification as configuration", func(t *testing.T) { t.Run("Testing notification as configuration", func(t *testing.T) {
setup := func() { setup := func() {
sqlStore = sqlstore.InitTestDB(t) sqlStore = sqlstore.InitTestDB(t)
orgFake = orgtest.NewOrgServiceFake()
nm := &notifications.NotificationService{} nm := &notifications.NotificationService{}
ns = alerting.ProvideService(sqlStore, encryptionService, nm) ns = alerting.ProvideService(sqlStore, encryptionService, nm)
@ -70,7 +72,7 @@ func TestNotificationAsConfig(t *testing.T) {
setup() setup()
_ = os.Setenv("TEST_VAR", "default") _ = os.Setenv("TEST_VAR", "default")
cfgProvider := &configReader{ cfgProvider := &configReader{
orgStore: sqlStore, orgService: orgFake,
encryptionService: encryptionService, encryptionService: encryptionService,
log: log.New("test logger"), log: log.New("test logger"),
} }
@ -150,7 +152,7 @@ func TestNotificationAsConfig(t *testing.T) {
setup() setup()
fakeAlertNotification := &fakeAlertNotification{} fakeAlertNotification := &fakeAlertNotification{}
fakeAlertNotification.ExpectedAlertNotification = &models.AlertNotification{OrgId: 1} fakeAlertNotification.ExpectedAlertNotification = &models.AlertNotification{OrgId: 1}
dc := newNotificationProvisioner(orgService, sqlStore, fakeAlertNotification, encryptionService, nil, logger) dc := newNotificationProvisioner(orgService, fakeAlertNotification, encryptionService, nil, logger)
err := dc.applyChanges(context.Background(), twoNotificationsConfig) err := dc.applyChanges(context.Background(), twoNotificationsConfig)
if err != nil { if err != nil {
@ -176,7 +178,7 @@ func TestNotificationAsConfig(t *testing.T) {
require.Equal(t, len(notificationsQuery.Result), 1) require.Equal(t, len(notificationsQuery.Result), 1)
t.Run("should update one notification", func(t *testing.T) { t.Run("should update one notification", func(t *testing.T) {
dc := newNotificationProvisioner(orgService, sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger)
err = dc.applyChanges(context.Background(), twoNotificationsConfig) err = dc.applyChanges(context.Background(), twoNotificationsConfig)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -186,7 +188,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Two notifications with is_default", func(t *testing.T) { t.Run("Two notifications with is_default", func(t *testing.T) {
setup() setup()
dc := newNotificationProvisioner(orgService, sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger)
err := dc.applyChanges(context.Background(), doubleNotificationsConfig) err := dc.applyChanges(context.Background(), doubleNotificationsConfig)
t.Run("should both be inserted", func(t *testing.T) { t.Run("should both be inserted", func(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
@ -221,7 +223,7 @@ func TestNotificationAsConfig(t *testing.T) {
require.Equal(t, len(notificationsQuery.Result), 2) require.Equal(t, len(notificationsQuery.Result), 2)
t.Run("should have two new notifications", func(t *testing.T) { t.Run("should have two new notifications", func(t *testing.T) {
dc := newNotificationProvisioner(orgService, sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger)
err := dc.applyChanges(context.Background(), twoNotificationsConfig) err := dc.applyChanges(context.Background(), twoNotificationsConfig)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -233,25 +235,16 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Can read correct properties with orgName instead of orgId", func(t *testing.T) { t.Run("Can read correct properties with orgName instead of orgId", func(t *testing.T) {
setup() setup()
existingOrg1 := models.GetOrgByNameQuery{Name: "Main Org. 1"}
err := sqlStore.GetOrgByNameHandler(context.Background(), &existingOrg1)
require.NoError(t, err)
require.NotNil(t, existingOrg1.Result)
existingOrg2 := models.GetOrgByNameQuery{Name: "Main Org. 2"}
err = sqlStore.GetOrgByNameHandler(context.Background(), &existingOrg2)
require.NoError(t, err)
require.NotNil(t, existingOrg2.Result)
existingNotificationCmd := models.CreateAlertNotificationCommand{ existingNotificationCmd := models.CreateAlertNotificationCommand{
Name: "default-notification-delete", Name: "default-notification-delete",
OrgId: existingOrg2.Result.Id, OrgId: 1,
Uid: "notifier2", Uid: "notifier2",
Type: "slack", Type: "slack",
} }
err = ns.SQLStore.CreateAlertNotificationCommand(context.Background(), &existingNotificationCmd) err := ns.SQLStore.CreateAlertNotificationCommand(context.Background(), &existingNotificationCmd)
require.NoError(t, err) require.NoError(t, err)
dc := newNotificationProvisioner(orgService, sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger)
err = dc.applyChanges(context.Background(), correctPropertiesWithOrgName) err = dc.applyChanges(context.Background(), correctPropertiesWithOrgName)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -260,7 +253,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Config doesn't contain required field", func(t *testing.T) { t.Run("Config doesn't contain required field", func(t *testing.T) {
setup() setup()
dc := newNotificationProvisioner(orgService, sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger)
err := dc.applyChanges(context.Background(), noRequiredFields) err := dc.applyChanges(context.Background(), noRequiredFields)
require.NotNil(t, err) require.NotNil(t, err)
@ -274,7 +267,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Empty yaml file", func(t *testing.T) { t.Run("Empty yaml file", func(t *testing.T) {
t.Run("should have not changed repo", func(t *testing.T) { t.Run("should have not changed repo", func(t *testing.T) {
setup() setup()
dc := newNotificationProvisioner(orgService, sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger)
err := dc.applyChanges(context.Background(), emptyFile) err := dc.applyChanges(context.Background(), emptyFile)
if err != nil { if err != nil {
t.Fatalf("applyChanges return an error %v", err) t.Fatalf("applyChanges return an error %v", err)
@ -288,7 +281,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Broken yaml should return error", func(t *testing.T) { t.Run("Broken yaml should return error", func(t *testing.T) {
reader := &configReader{ reader := &configReader{
orgStore: sqlStore, orgService: orgFake,
encryptionService: encryptionService, encryptionService: encryptionService,
log: log.New("test logger"), log: log.New("test logger"),
} }
@ -299,7 +292,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Skip invalid directory", func(t *testing.T) { t.Run("Skip invalid directory", func(t *testing.T) {
cfgProvider := &configReader{ cfgProvider := &configReader{
orgStore: sqlStore, orgService: orgFake,
encryptionService: encryptionService, encryptionService: encryptionService,
log: log.New("test logger"), log: log.New("test logger"),
} }
@ -313,7 +306,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Unknown notifier should return error", func(t *testing.T) { t.Run("Unknown notifier should return error", func(t *testing.T) {
cfgProvider := &configReader{ cfgProvider := &configReader{
orgStore: sqlStore, orgService: orgFake,
encryptionService: encryptionService, encryptionService: encryptionService,
log: log.New("test logger"), log: log.New("test logger"),
} }
@ -324,7 +317,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Read incorrect properties", func(t *testing.T) { t.Run("Read incorrect properties", func(t *testing.T) {
cfgProvider := &configReader{ cfgProvider := &configReader{
orgStore: sqlStore, orgService: orgFake,
encryptionService: encryptionService, encryptionService: encryptionService,
log: log.New("test logger"), log: log.New("test logger"),
} }

View File

@ -26,7 +26,6 @@ import (
"github.com/grafana/grafana/pkg/services/provisioning/datasources" "github.com/grafana/grafana/pkg/services/provisioning/datasources"
"github.com/grafana/grafana/pkg/services/provisioning/notifiers" "github.com/grafana/grafana/pkg/services/provisioning/notifiers"
"github.com/grafana/grafana/pkg/services/provisioning/plugins" "github.com/grafana/grafana/pkg/services/provisioning/plugins"
"github.com/grafana/grafana/pkg/services/provisioning/utils"
"github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/quota"
"github.com/grafana/grafana/pkg/services/searchV2" "github.com/grafana/grafana/pkg/services/searchV2"
"github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets"
@ -107,8 +106,8 @@ func NewProvisioningServiceImpl() *ProvisioningServiceImpl {
// Used for testing purposes // Used for testing purposes
func newProvisioningServiceImpl( func newProvisioningServiceImpl(
newDashboardProvisioner dashboards.DashboardProvisionerFactory, newDashboardProvisioner dashboards.DashboardProvisionerFactory,
provisionNotifiers func(context.Context, string, notifiers.Manager, org.Service, notifiers.SQLStore, encryption.Internal, *notifications.NotificationService) error, provisionNotifiers func(context.Context, string, notifiers.Manager, org.Service, encryption.Internal, *notifications.NotificationService) error,
provisionDatasources func(context.Context, string, datasources.Store, datasources.CorrelationsStore, utils.OrgStore) error, provisionDatasources func(context.Context, string, datasources.Store, datasources.CorrelationsStore, org.Service) error,
provisionPlugins func(context.Context, string, plugifaces.Store, pluginsettings.Service, org.Service) error, provisionPlugins func(context.Context, string, plugifaces.Store, pluginsettings.Service, org.Service) error,
) *ProvisioningServiceImpl { ) *ProvisioningServiceImpl {
return &ProvisioningServiceImpl{ return &ProvisioningServiceImpl{
@ -132,8 +131,8 @@ type ProvisioningServiceImpl struct {
pollingCtxCancel context.CancelFunc pollingCtxCancel context.CancelFunc
newDashboardProvisioner dashboards.DashboardProvisionerFactory newDashboardProvisioner dashboards.DashboardProvisionerFactory
dashboardProvisioner dashboards.DashboardProvisioner dashboardProvisioner dashboards.DashboardProvisioner
provisionNotifiers func(context.Context, string, notifiers.Manager, org.Service, notifiers.SQLStore, encryption.Internal, *notifications.NotificationService) error provisionNotifiers func(context.Context, string, notifiers.Manager, org.Service, encryption.Internal, *notifications.NotificationService) error
provisionDatasources func(context.Context, string, datasources.Store, datasources.CorrelationsStore, utils.OrgStore) error provisionDatasources func(context.Context, string, datasources.Store, datasources.CorrelationsStore, org.Service) error
provisionPlugins func(context.Context, string, plugifaces.Store, pluginsettings.Service, org.Service) error provisionPlugins func(context.Context, string, plugifaces.Store, pluginsettings.Service, org.Service) error
provisionAlerting func(context.Context, prov_alerting.ProvisionerConfig) error provisionAlerting func(context.Context, prov_alerting.ProvisionerConfig) error
mutex sync.Mutex mutex sync.Mutex
@ -206,7 +205,7 @@ func (ps *ProvisioningServiceImpl) Run(ctx context.Context) error {
func (ps *ProvisioningServiceImpl) ProvisionDatasources(ctx context.Context) error { func (ps *ProvisioningServiceImpl) ProvisionDatasources(ctx context.Context) error {
datasourcePath := filepath.Join(ps.Cfg.ProvisioningPath, "datasources") datasourcePath := filepath.Join(ps.Cfg.ProvisioningPath, "datasources")
if err := ps.provisionDatasources(ctx, datasourcePath, ps.datasourceService, ps.correlationsService, ps.SQLStore); err != nil { if err := ps.provisionDatasources(ctx, datasourcePath, ps.datasourceService, ps.correlationsService, ps.orgService); err != nil {
err = fmt.Errorf("%v: %w", "Datasource provisioning error", err) err = fmt.Errorf("%v: %w", "Datasource provisioning error", err)
ps.log.Error("Failed to provision data sources", "error", err) ps.log.Error("Failed to provision data sources", "error", err)
return err return err
@ -226,7 +225,7 @@ func (ps *ProvisioningServiceImpl) ProvisionPlugins(ctx context.Context) error {
func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) error { func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) error {
alertNotificationsPath := filepath.Join(ps.Cfg.ProvisioningPath, "notifiers") alertNotificationsPath := filepath.Join(ps.Cfg.ProvisioningPath, "notifiers")
if err := ps.provisionNotifiers(ctx, alertNotificationsPath, ps.alertingService, ps.orgService, ps.SQLStore, ps.EncryptionService, ps.NotificationService); err != nil { if err := ps.provisionNotifiers(ctx, alertNotificationsPath, ps.alertingService, ps.orgService, ps.EncryptionService, ps.NotificationService); err != nil {
err = fmt.Errorf("%v: %w", "Alert notification provisioning error", err) err = fmt.Errorf("%v: %w", "Alert notification provisioning error", err)
ps.log.Error("Failed to provision alert notifications", "error", err) ps.log.Error("Failed to provision alert notifications", "error", err)
return err return err
@ -236,7 +235,7 @@ func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) e
func (ps *ProvisioningServiceImpl) ProvisionDashboards(ctx context.Context) error { func (ps *ProvisioningServiceImpl) ProvisionDashboards(ctx context.Context) error {
dashboardPath := filepath.Join(ps.Cfg.ProvisioningPath, "dashboards") dashboardPath := filepath.Join(ps.Cfg.ProvisioningPath, "dashboards")
dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardProvisioningService, ps.SQLStore, ps.dashboardService) dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardProvisioningService, ps.orgService, ps.dashboardService)
if err != nil { if err != nil {
return fmt.Errorf("%v: %w", "Failed to create provisioner", err) return fmt.Errorf("%v: %w", "Failed to create provisioner", err)
} }

View File

@ -7,6 +7,7 @@ import (
"time" "time"
dashboardstore "github.com/grafana/grafana/pkg/services/dashboards" dashboardstore "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/provisioning/dashboards" "github.com/grafana/grafana/pkg/services/provisioning/dashboards"
"github.com/grafana/grafana/pkg/services/provisioning/utils" "github.com/grafana/grafana/pkg/services/provisioning/utils"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
@ -93,7 +94,7 @@ func setup() *serviceTestStruct {
} }
serviceTest.service = newProvisioningServiceImpl( serviceTest.service = newProvisioningServiceImpl(
func(context.Context, string, dashboardstore.DashboardProvisioningService, utils.OrgStore, utils.DashboardStore) (dashboards.DashboardProvisioner, error) { func(context.Context, string, dashboardstore.DashboardProvisioningService, org.Service, utils.DashboardStore) (dashboards.DashboardProvisioner, error) {
return serviceTest.mock, nil return serviceTest.mock, nil
}, },
nil, nil,

View File

@ -6,19 +6,17 @@ import (
"fmt" "fmt"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
) )
type OrgStore interface {
GetOrgById(context.Context, *models.GetOrgByIdQuery) error
}
type DashboardStore interface { type DashboardStore interface {
GetDashboard(context.Context, *models.GetDashboardQuery) error GetDashboard(context.Context, *models.GetDashboardQuery) error
} }
func CheckOrgExists(ctx context.Context, store OrgStore, orgID int64) error { func CheckOrgExists(ctx context.Context, orgService org.Service, orgID int64) error {
query := models.GetOrgByIdQuery{Id: orgID} query := org.GetOrgByIdQuery{ID: orgID}
if err := store.GetOrgById(ctx, &query); err != nil { _, err := orgService.GetByID(ctx, &query)
if err != nil {
if errors.Is(err, models.ErrOrgNotFound) { if errors.Is(err, models.ErrOrgNotFound) {
return err return err
} }

View File

@ -13,7 +13,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/registry" "github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
@ -123,14 +122,14 @@ func (s *StandardSearchService) IsDisabled() bool {
} }
func (s *StandardSearchService) Run(ctx context.Context) error { func (s *StandardSearchService) Run(ctx context.Context) error {
orgQuery := &models.SearchOrgsQuery{} orgQuery := &org.SearchOrgsQuery{}
err := s.sql.SearchOrgs(ctx, orgQuery) result, err := s.orgService.Search(ctx, orgQuery)
if err != nil { if err != nil {
return fmt.Errorf("can't get org list: %w", err) return fmt.Errorf("can't get org list: %w", err)
} }
orgIDs := make([]int64, 0, len(orgQuery.Result)) orgIDs := make([]int64, 0, len(result))
for _, org := range orgQuery.Result { for _, org := range result {
orgIDs = append(orgIDs, org.Id) orgIDs = append(orgIDs, org.ID)
} }
return s.dashboardIndex.run(ctx, orgIDs, s.reIndexCh) return s.dashboardIndex.run(ctx, orgIDs, s.reIndexCh)
} }

View File

@ -14,79 +14,6 @@ import (
// MainOrgName is the name of the main organization. // MainOrgName is the name of the main organization.
const MainOrgName = "Main Org." const MainOrgName = "Main Org."
func (ss *SQLStore) SearchOrgs(ctx context.Context, query *models.SearchOrgsQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
query.Result = make([]*models.OrgDTO, 0)
sess := dbSession.Table("org")
if query.Query != "" {
sess.Where("name LIKE ?", query.Query+"%")
}
if query.Name != "" {
sess.Where("name=?", query.Name)
}
if len(query.Ids) > 0 {
sess.In("id", query.Ids)
}
if query.Limit > 0 {
sess.Limit(query.Limit, query.Limit*query.Page)
}
sess.Cols("id", "name")
err := sess.Find(&query.Result)
return err
})
}
func (ss *SQLStore) GetOrgById(ctx context.Context, query *models.GetOrgByIdQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
var org models.Org
exists, err := dbSession.ID(query.Id).Get(&org)
if err != nil {
return err
}
if !exists {
return models.ErrOrgNotFound
}
query.Result = &org
return nil
})
}
func (ss *SQLStore) GetOrgByNameHandler(ctx context.Context, query *models.GetOrgByNameQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
var org models.Org
exists, err := dbSession.Where("name=?", query.Name).Get(&org)
if err != nil {
return err
}
if !exists {
return models.ErrOrgNotFound
}
query.Result = &org
return nil
})
}
// GetOrgByName gets an organization by name.
func (ss *SQLStore) GetOrgByName(name string) (*models.Org, error) {
var org models.Org
exists, err := ss.engine.Where("name=?", name).Get(&org)
if err != nil {
return nil, err
}
if !exists {
return nil, models.ErrOrgNotFound
}
return &org, nil
}
func isOrgNameTaken(name string, existingId int64, sess *DBSession) (bool, error) { func isOrgNameTaken(name string, existingId int64, sess *DBSession) (bool, error) {
// check if org name is taken // check if org name is taken
var org models.Org var org models.Org

View File

@ -24,59 +24,6 @@ func TestIntegrationAccountDataAccess(t *testing.T) {
t.Run("Testing Account DB Access", func(t *testing.T) { t.Run("Testing Account DB Access", func(t *testing.T) {
sqlStore := InitTestDB(t) sqlStore := InitTestDB(t)
t.Run("Given we have organizations, we can query them by IDs", func(t *testing.T) {
var err error
var cmd *models.CreateOrgCommand
ids := []int64{}
for i := 1; i < 4; i++ {
cmd = &models.CreateOrgCommand{Name: fmt.Sprint("Org #", i)}
err = sqlStore.CreateOrg(context.Background(), cmd)
require.NoError(t, err)
ids = append(ids, cmd.Result.Id)
}
query := &models.SearchOrgsQuery{Ids: ids}
err = sqlStore.SearchOrgs(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(query.Result), 3)
})
t.Run("Given we have organizations, we can limit and paginate search", func(t *testing.T) {
sqlStore = InitTestDB(t)
for i := 1; i < 4; i++ {
cmd := &models.CreateOrgCommand{Name: fmt.Sprint("Org #", i)}
err := sqlStore.CreateOrg(context.Background(), cmd)
require.NoError(t, err)
}
t.Run("Should be able to search with defaults", func(t *testing.T) {
query := &models.SearchOrgsQuery{}
err := sqlStore.SearchOrgs(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(query.Result), 3)
})
t.Run("Should be able to limit search", func(t *testing.T) {
query := &models.SearchOrgsQuery{Limit: 1}
err := sqlStore.SearchOrgs(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(query.Result), 1)
})
t.Run("Should be able to limit and paginate search", func(t *testing.T) {
query := &models.SearchOrgsQuery{Limit: 2, Page: 1}
err := sqlStore.SearchOrgs(context.Background(), query)
require.NoError(t, err)
require.Equal(t, len(query.Result), 1)
})
})
t.Run("Given single org mode", func(t *testing.T) { t.Run("Given single org mode", func(t *testing.T) {
sqlStore.Cfg.AutoAssignOrg = true sqlStore.Cfg.AutoAssignOrg = true
sqlStore.Cfg.AutoAssignOrgId = 1 sqlStore.Cfg.AutoAssignOrgId = 1

View File

@ -80,39 +80,27 @@ func populateDB(t *testing.T, sqlStore *SQLStore) {
users[i] = *user users[i] = *user
} }
// get 1st user's organisation
getOrgByIdQuery := &models.GetOrgByIdQuery{Id: users[0].OrgID}
err := sqlStore.GetOrgById(context.Background(), getOrgByIdQuery)
require.NoError(t, err)
orga := getOrgByIdQuery.Result
// add 2nd user as editor // add 2nd user as editor
cmd := &models.AddOrgUserCommand{ cmd := &models.AddOrgUserCommand{
OrgId: orga.Id, OrgId: users[0].OrgID,
UserId: users[1].ID, UserId: users[1].ID,
Role: org.RoleEditor, Role: org.RoleEditor,
} }
err = sqlStore.AddOrgUser(context.Background(), cmd) err := sqlStore.AddOrgUser(context.Background(), cmd)
require.NoError(t, err) require.NoError(t, err)
// add 3rd user as viewer // add 3rd user as viewer
cmd = &models.AddOrgUserCommand{ cmd = &models.AddOrgUserCommand{
OrgId: orga.Id, OrgId: users[0].OrgID,
UserId: users[2].ID, UserId: users[2].ID,
Role: org.RoleViewer, Role: org.RoleViewer,
} }
err = sqlStore.AddOrgUser(context.Background(), cmd) err = sqlStore.AddOrgUser(context.Background(), cmd)
require.NoError(t, err) require.NoError(t, err)
// get 2nd user's organisation
getOrgByIdQuery = &models.GetOrgByIdQuery{Id: users[1].OrgID}
err = sqlStore.GetOrgById(context.Background(), getOrgByIdQuery)
require.NoError(t, err)
orga = getOrgByIdQuery.Result
// add 1st user as admin // add 1st user as admin
cmd = &models.AddOrgUserCommand{ cmd = &models.AddOrgUserCommand{
OrgId: orga.Id, OrgId: users[1].OrgID,
UserId: users[0].ID, UserId: users[0].ID,
Role: org.RoleAdmin, Role: org.RoleAdmin,
} }

View File

@ -18,9 +18,6 @@ type Store interface {
GetDialect() migrator.Dialect GetDialect() migrator.Dialect
GetDBType() core.DbType GetDBType() core.DbType
GetSystemStats(ctx context.Context, query *models.GetSystemStatsQuery) error GetSystemStats(ctx context.Context, query *models.GetSystemStatsQuery) error
GetOrgByName(name string) (*models.Org, error)
GetOrgById(context.Context, *models.GetOrgByIdQuery) error
GetOrgByNameHandler(ctx context.Context, query *models.GetOrgByNameQuery) error
CreateUser(ctx context.Context, cmd user.CreateUserCommand) (*user.User, error) CreateUser(ctx context.Context, cmd user.CreateUserCommand) (*user.User, error)
GetUserProfile(ctx context.Context, query *models.GetUserProfileQuery) error GetUserProfile(ctx context.Context, query *models.GetUserProfileQuery) error
GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error
@ -40,6 +37,5 @@ type Store interface {
Reset() error Reset() error
Quote(value string) string Quote(value string) string
GetDBHealthQuery(ctx context.Context, query *models.GetDBHealthQuery) error GetDBHealthQuery(ctx context.Context, query *models.GetDBHealthQuery) error
SearchOrgs(ctx context.Context, query *models.SearchOrgsQuery) error
GetSqlxSession() *session.SessionDB GetSqlxSession() *session.SessionDB
} }

View File

@ -82,13 +82,9 @@ func SetUpDatabase(t *testing.T, grafDir string) *sqlstore.SQLStore {
sqlStore := sqlstore.InitTestDB(t, sqlstore.InitTestDBOpt{ sqlStore := sqlstore.InitTestDB(t, sqlstore.InitTestDBOpt{
EnsureDefaultOrgAndUser: true, EnsureDefaultOrgAndUser: true,
}) })
// We need the main org, since it's used for anonymous access
org, err := sqlStore.GetOrgByName(sqlstore.MainOrgName)
require.NoError(t, err)
require.NotNil(t, org)
// Make sure changes are synced with other goroutines // Make sure changes are synced with other goroutines
err = sqlStore.Sync() err := sqlStore.Sync()
require.NoError(t, err) require.NoError(t, err)
return sqlStore return sqlStore