mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 16:32:13 +08:00
FeatureFlags: Use interface rather than manager (#80000)
This commit is contained in:
@ -600,7 +600,7 @@ func (hs *HTTPServer) GetAnnotationTags(c *contextmodel.ReqContext) response.Res
|
||||
// where <type> is the type of annotation with id <id>.
|
||||
// If annotationPermissionUpdate feature toggle is enabled, dashboard annotation scope will be resolved to the corresponding
|
||||
// dashboard and folder scopes (eg, "dashboards:uid:<annotation_dashboard_uid>", "folders:uid:<parent_folder_uid>" etc).
|
||||
func AnnotationTypeScopeResolver(annotationsRepo annotations.Repository, features *featuremgmt.FeatureManager, dashSvc dashboards.DashboardService, folderSvc folder.Service) (string, accesscontrol.ScopeAttributeResolver) {
|
||||
func AnnotationTypeScopeResolver(annotationsRepo annotations.Repository, features featuremgmt.FeatureToggles, dashSvc dashboards.DashboardService, folderSvc folder.Service) (string, accesscontrol.ScopeAttributeResolver) {
|
||||
prefix := accesscontrol.ScopeAnnotationsProvider.GetResourceScope("")
|
||||
return prefix, accesscontrol.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, initialScope string) ([]string, error) {
|
||||
scopeParts := strings.Split(initialScope, ":")
|
||||
|
@ -258,7 +258,7 @@ func userWithPermissions(orgID int64, permissions []accesscontrol.Permission) *u
|
||||
return &user.SignedInUser{IsAnonymous: true, OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(permissions)}}
|
||||
}
|
||||
|
||||
func setupSimpleHTTPServer(features *featuremgmt.FeatureManager) *HTTPServer {
|
||||
func setupSimpleHTTPServer(features featuremgmt.FeatureToggles) *HTTPServer {
|
||||
if features == nil {
|
||||
features = featuremgmt.WithFeatures()
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ func validateURL(cmdType string, url string) response.Response {
|
||||
// validateJSONData prevents the user from adding a custom header with name that matches the auth proxy header name.
|
||||
// This is done to prevent data source proxy from being used to circumvent auth proxy.
|
||||
// For more context take a look at CVE-2022-35957
|
||||
func validateJSONData(ctx context.Context, jsonData *simplejson.Json, cfg *setting.Cfg, features *featuremgmt.FeatureManager) error {
|
||||
func validateJSONData(ctx context.Context, jsonData *simplejson.Json, cfg *setting.Cfg, features featuremgmt.FeatureToggles) error {
|
||||
if jsonData == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ func (hs *HTTPServer) GetFeatureToggles(ctx *contextmodel.ReqContext) response.R
|
||||
dtos := make([]featuremgmt.FeatureToggleDTO, 0)
|
||||
|
||||
// loop through features an add features that should be visible to dtos
|
||||
for _, ft := range hs.Features.GetFlags() {
|
||||
for _, ft := range hs.featureManager.GetFlags() {
|
||||
if isFeatureHidden(ft, cfg.HiddenToggles) {
|
||||
continue
|
||||
}
|
||||
@ -67,7 +67,7 @@ func (hs *HTTPServer) UpdateFeatureToggle(ctx *contextmodel.ReqContext) response
|
||||
|
||||
for _, t := range cmd.FeatureToggles {
|
||||
// make sure flag exists, and only continue if flag is writeable
|
||||
if f, ok := hs.Features.LookupFlag(t.Name); ok && isFeatureWriteable(f, hs.Cfg.FeatureManagement.ReadOnlyToggles) {
|
||||
if f, ok := hs.featureManager.LookupFlag(t.Name); ok && isFeatureWriteable(f, hs.Cfg.FeatureManagement.ReadOnlyToggles) {
|
||||
hs.log.Info("UpdateFeatureToggle: updating toggle", "toggle_name", t.Name, "enabled", t.Enabled, "username", ctx.SignedInUser.Login)
|
||||
payload.FeatureToggles[t.Name] = strconv.FormatBool(t.Enabled)
|
||||
} else {
|
||||
@ -82,13 +82,13 @@ func (hs *HTTPServer) UpdateFeatureToggle(ctx *contextmodel.ReqContext) response
|
||||
return response.Respond(http.StatusBadRequest, "Failed to perform webhook request")
|
||||
}
|
||||
|
||||
hs.Features.SetRestartRequired()
|
||||
hs.featureManager.SetRestartRequired()
|
||||
|
||||
return response.Respond(http.StatusOK, "feature toggles updated successfully")
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) GetFeatureMgmtState(ctx *contextmodel.ReqContext) response.Response {
|
||||
fmState := hs.Features.GetState()
|
||||
fmState := hs.featureManager.GetState()
|
||||
return response.Respond(http.StatusOK, fmState)
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,9 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@ -16,8 +19,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web/webtest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetFeatureToggles(t *testing.T) {
|
||||
@ -405,13 +406,16 @@ func runGetScenario(
|
||||
cfg := setting.NewCfg()
|
||||
cfg.FeatureManagement = settings
|
||||
|
||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = cfg
|
||||
hs.Features = featuremgmt.WithFeatureFlags(append([]*featuremgmt.FeatureFlag{{
|
||||
fm := featuremgmt.WithFeatureFlags(append([]*featuremgmt.FeatureFlag{{
|
||||
Name: featuremgmt.FlagFeatureToggleAdminPage,
|
||||
Enabled: true,
|
||||
Stage: featuremgmt.FeatureStageGeneralAvailability,
|
||||
}}, features...))
|
||||
|
||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = cfg
|
||||
hs.Features = fm
|
||||
hs.featureManager = fm
|
||||
hs.orgService = orgtest.NewOrgServiceFake()
|
||||
hs.userService = &usertest.FakeUserService{
|
||||
ExpectedUser: &user.User{ID: 1},
|
||||
@ -469,13 +473,16 @@ func runSetScenario(
|
||||
cfg := setting.NewCfg()
|
||||
cfg.FeatureManagement = settings
|
||||
|
||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = cfg
|
||||
hs.Features = featuremgmt.WithFeatureFlags(append([]*featuremgmt.FeatureFlag{{
|
||||
features := featuremgmt.WithFeatureFlags(append([]*featuremgmt.FeatureFlag{{
|
||||
Name: featuremgmt.FlagFeatureToggleAdminPage,
|
||||
Enabled: true,
|
||||
Stage: featuremgmt.FeatureStageGeneralAvailability,
|
||||
}}, serverFeatures...))
|
||||
|
||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = cfg
|
||||
hs.Features = features
|
||||
hs.featureManager = features
|
||||
hs.orgService = orgtest.NewOrgServiceFake()
|
||||
hs.userService = &usertest.FakeUserService{
|
||||
ExpectedUser: &user.User{ID: 1},
|
||||
|
@ -95,7 +95,7 @@ func BenchmarkFolderListAndSearch(b *testing.B) {
|
||||
desc string
|
||||
url string
|
||||
expectedLen int
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
}{
|
||||
{
|
||||
desc: "impl=default nested_folders=on get root folders",
|
||||
@ -423,7 +423,7 @@ func setupDB(b testing.TB) benchScenario {
|
||||
}
|
||||
}
|
||||
|
||||
func setupServer(b testing.TB, sc benchScenario, features *featuremgmt.FeatureManager) *web.Macaron {
|
||||
func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureToggles) *web.Macaron {
|
||||
b.Helper()
|
||||
|
||||
m := web.New()
|
||||
|
@ -435,7 +435,7 @@ func TestFolderGetAPIEndpoint(t *testing.T) {
|
||||
type testCase struct {
|
||||
description string
|
||||
URL string
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
expectedCode int
|
||||
expectedParentUIDs []string
|
||||
expectedParentOrgIDs []int64
|
||||
|
@ -32,7 +32,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features *featuremgmt.FeatureManager, pstore pluginstore.Store, psettings pluginsettings.Service) (*web.Mux, *HTTPServer) {
|
||||
func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features featuremgmt.FeatureToggles, pstore pluginstore.Store, psettings pluginsettings.Service) (*web.Mux, *HTTPServer) {
|
||||
t.Helper()
|
||||
db.InitTestDB(t)
|
||||
// nolint:staticcheck
|
||||
|
@ -126,7 +126,8 @@ type HTTPServer struct {
|
||||
RouteRegister routing.RouteRegister
|
||||
RenderService rendering.Service
|
||||
Cfg *setting.Cfg
|
||||
Features *featuremgmt.FeatureManager
|
||||
Features featuremgmt.FeatureToggles
|
||||
featureManager *featuremgmt.FeatureManager
|
||||
SettingsProvider setting.Provider
|
||||
HooksService *hooks.HooksService
|
||||
navTreeService navtree.Service
|
||||
@ -290,7 +291,8 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
||||
ShortURLService: shortURLService,
|
||||
QueryHistoryService: queryHistoryService,
|
||||
CorrelationsService: correlationsService,
|
||||
Features: features,
|
||||
Features: features, // a read only view of the managers state
|
||||
featureManager: features,
|
||||
StorageService: storageService,
|
||||
RemoteCacheService: remoteCache,
|
||||
ProvisioningService: provisioningService,
|
||||
|
@ -382,7 +382,7 @@ func createService(t testing.TB, cfg *setting.Cfg, store db.DB, statsService sta
|
||||
store,
|
||||
&mockSocial{},
|
||||
&pluginstore.FakePluginStore{},
|
||||
featuremgmt.WithFeatures("feature1", "feature2"),
|
||||
featuremgmt.WithManager("feature1", "feature2"),
|
||||
o.datasources,
|
||||
httpclient.NewProvider(sdkhttpclient.ProviderOptions{Middlewares: []sdkhttpclient.Middleware{}}),
|
||||
)
|
||||
|
@ -72,10 +72,10 @@ type keySetJWKS struct {
|
||||
jose.JSONWebKeySet
|
||||
}
|
||||
|
||||
func NewAzureADProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features *featuremgmt.FeatureManager, cache remotecache.CacheStorage) *SocialAzureAD {
|
||||
func NewAzureADProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles, cache remotecache.CacheStorage) *SocialAzureAD {
|
||||
config := createOAuthConfig(info, cfg, social.AzureADProviderName)
|
||||
provider := &SocialAzureAD{
|
||||
SocialBase: newSocialBase(social.AzureADProviderName, config, info, cfg.AutoAssignOrgRole, *features),
|
||||
SocialBase: newSocialBase(social.AzureADProviderName, config, info, cfg.AutoAssignOrgRole, features),
|
||||
cache: cache,
|
||||
allowedOrganizations: util.SplitString(info.Extra[allowedOrganizationsKey]),
|
||||
forceUseGraphAPI: MustBool(info.Extra[forceUseGraphAPIKey], false),
|
||||
|
@ -45,10 +45,10 @@ type SocialGenericOAuth struct {
|
||||
teamIds []string
|
||||
}
|
||||
|
||||
func NewGenericOAuthProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features *featuremgmt.FeatureManager) *SocialGenericOAuth {
|
||||
func NewGenericOAuthProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGenericOAuth {
|
||||
config := createOAuthConfig(info, cfg, social.GenericOAuthProviderName)
|
||||
provider := &SocialGenericOAuth{
|
||||
SocialBase: newSocialBase(social.GenericOAuthProviderName, config, info, cfg.AutoAssignOrgRole, *features),
|
||||
SocialBase: newSocialBase(social.GenericOAuthProviderName, config, info, cfg.AutoAssignOrgRole, features),
|
||||
teamsUrl: info.TeamsUrl,
|
||||
emailAttributeName: info.EmailAttributeName,
|
||||
emailAttributePath: info.EmailAttributePath,
|
||||
|
@ -53,13 +53,13 @@ var (
|
||||
"User is not a member of one of the required organizations. Please contact identity provider administrator."))
|
||||
)
|
||||
|
||||
func NewGitHubProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features *featuremgmt.FeatureManager) *SocialGithub {
|
||||
func NewGitHubProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGithub {
|
||||
teamIdsSplitted := util.SplitString(info.Extra[teamIdsKey])
|
||||
teamIds := mustInts(teamIdsSplitted)
|
||||
|
||||
config := createOAuthConfig(info, cfg, social.GitHubProviderName)
|
||||
provider := &SocialGithub{
|
||||
SocialBase: newSocialBase(social.GitHubProviderName, config, info, cfg.AutoAssignOrgRole, *features),
|
||||
SocialBase: newSocialBase(social.GitHubProviderName, config, info, cfg.AutoAssignOrgRole, features),
|
||||
teamIds: teamIds,
|
||||
allowedOrganizations: util.SplitString(info.Extra[allowedOrganizationsKey]),
|
||||
}
|
||||
|
@ -52,10 +52,10 @@ type userData struct {
|
||||
IsGrafanaAdmin *bool `json:"-"`
|
||||
}
|
||||
|
||||
func NewGitLabProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features *featuremgmt.FeatureManager) *SocialGitlab {
|
||||
func NewGitLabProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGitlab {
|
||||
config := createOAuthConfig(info, cfg, social.GitlabProviderName)
|
||||
provider := &SocialGitlab{
|
||||
SocialBase: newSocialBase(social.GitlabProviderName, config, info, cfg.AutoAssignOrgRole, *features),
|
||||
SocialBase: newSocialBase(social.GitlabProviderName, config, info, cfg.AutoAssignOrgRole, features),
|
||||
}
|
||||
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) {
|
||||
|
@ -38,10 +38,10 @@ type googleUserData struct {
|
||||
rawJSON []byte `json:"-"`
|
||||
}
|
||||
|
||||
func NewGoogleProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features *featuremgmt.FeatureManager) *SocialGoogle {
|
||||
func NewGoogleProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGoogle {
|
||||
config := createOAuthConfig(info, cfg, social.GoogleProviderName)
|
||||
provider := &SocialGoogle{
|
||||
SocialBase: newSocialBase(social.GoogleProviderName, config, info, cfg.AutoAssignOrgRole, *features),
|
||||
SocialBase: newSocialBase(social.GoogleProviderName, config, info, cfg.AutoAssignOrgRole, features),
|
||||
}
|
||||
|
||||
if strings.HasPrefix(info.ApiUrl, legacyAPIURL) {
|
||||
|
@ -33,7 +33,7 @@ type OrgRecord struct {
|
||||
Login string `json:"login"`
|
||||
}
|
||||
|
||||
func NewGrafanaComProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features *featuremgmt.FeatureManager) *SocialGrafanaCom {
|
||||
func NewGrafanaComProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGrafanaCom {
|
||||
// Override necessary settings
|
||||
info.AuthUrl = cfg.GrafanaComURL + "/oauth2/authorize"
|
||||
info.TokenUrl = cfg.GrafanaComURL + "/api/oauth2/token"
|
||||
@ -41,7 +41,7 @@ func NewGrafanaComProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings
|
||||
|
||||
config := createOAuthConfig(info, cfg, social.GrafanaComProviderName)
|
||||
provider := &SocialGrafanaCom{
|
||||
SocialBase: newSocialBase(social.GrafanaComProviderName, config, info, cfg.AutoAssignOrgRole, *features),
|
||||
SocialBase: newSocialBase(social.GrafanaComProviderName, config, info, cfg.AutoAssignOrgRole, features),
|
||||
url: cfg.GrafanaComURL,
|
||||
allowedOrganizations: util.SplitString(info.Extra[allowedOrganizationsKey]),
|
||||
}
|
||||
|
@ -44,10 +44,10 @@ type OktaClaims struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func NewOktaProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features *featuremgmt.FeatureManager) *SocialOkta {
|
||||
func NewOktaProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialOkta {
|
||||
config := createOAuthConfig(info, cfg, social.OktaProviderName)
|
||||
provider := &SocialOkta{
|
||||
SocialBase: newSocialBase(social.OktaProviderName, config, info, cfg.AutoAssignOrgRole, *features),
|
||||
SocialBase: newSocialBase(social.OktaProviderName, config, info, cfg.AutoAssignOrgRole, features),
|
||||
}
|
||||
|
||||
if info.UseRefreshToken {
|
||||
|
@ -26,14 +26,14 @@ type SocialBase struct {
|
||||
info *social.OAuthInfo
|
||||
log log.Logger
|
||||
autoAssignOrgRole string
|
||||
features featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
func newSocialBase(name string,
|
||||
config *oauth2.Config,
|
||||
info *social.OAuthInfo,
|
||||
autoAssignOrgRole string,
|
||||
features featuremgmt.FeatureManager,
|
||||
features featuremgmt.FeatureToggles,
|
||||
) *SocialBase {
|
||||
logger := log.New("oauth." + name)
|
||||
|
||||
|
@ -37,7 +37,7 @@ type SocialService struct {
|
||||
}
|
||||
|
||||
func ProvideService(cfg *setting.Cfg,
|
||||
features *featuremgmt.FeatureManager,
|
||||
features featuremgmt.FeatureToggles,
|
||||
usageStats usagestats.Service,
|
||||
bundleRegistry supportbundles.Service,
|
||||
cache remotecache.CacheStorage,
|
||||
@ -228,7 +228,7 @@ func (ss *SocialService) getUsageStats(ctx context.Context) (map[string]any, err
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func createOAuthConnector(name string, info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features *featuremgmt.FeatureManager, cache remotecache.CacheStorage) (social.SocialConnector, error) {
|
||||
func createOAuthConnector(name string, info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles, cache remotecache.CacheStorage) (social.SocialConnector, error) {
|
||||
switch name {
|
||||
case social.AzureADProviderName:
|
||||
return connectors.NewAzureADProvider(info, cfg, ssoSettings, features, cache), nil
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
|
||||
func TestSocialService_ProvideService(t *testing.T) {
|
||||
type testEnv struct {
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
@ -3,8 +3,8 @@ package config
|
||||
import (
|
||||
"github.com/grafana/grafana-azure-sdk-go/azsettings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/log"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@ -44,7 +44,7 @@ type Cfg struct {
|
||||
GrafanaAppURL string
|
||||
GrafanaAppSubURL string
|
||||
|
||||
Features plugins.FeatureToggles
|
||||
Features featuremgmt.FeatureToggles
|
||||
|
||||
AngularSupportEnabled bool
|
||||
HideAngularDeprecation []string
|
||||
@ -52,7 +52,7 @@ type Cfg struct {
|
||||
|
||||
func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string,
|
||||
awsAllowedAuthProviders []string, awsAssumeRoleEnabled bool, awsExternalId string, azure *azsettings.AzureSettings, secureSocksDSProxy setting.SecureSocksDSProxySettings,
|
||||
grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, appURL string, appSubURL string, tracing Tracing, features plugins.FeatureToggles, angularSupportEnabled bool,
|
||||
grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, appURL string, appSubURL string, tracing Tracing, features featuremgmt.FeatureToggles, angularSupportEnabled bool,
|
||||
grafanaComURL string, disablePlugins []string, hideAngularDeprecation []string, forwardHostEnvVars []string) *Cfg {
|
||||
return &Cfg{
|
||||
log: log.New("plugin.cfg"),
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana-azure-sdk-go/azsettings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/auth"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
@ -726,27 +727,27 @@ func TestService_GetConfigMap(t *testing.T) {
|
||||
func TestService_GetConfigMap_featureToggles(t *testing.T) {
|
||||
t.Run("Feature toggles list is deterministic", func(t *testing.T) {
|
||||
tcs := []struct {
|
||||
enabledFeatures []string
|
||||
features featuremgmt.FeatureToggles
|
||||
expectedConfig map[string]string
|
||||
}{
|
||||
{
|
||||
enabledFeatures: nil,
|
||||
features: nil,
|
||||
expectedConfig: map[string]string{},
|
||||
},
|
||||
{
|
||||
enabledFeatures: []string{},
|
||||
features: featuremgmt.WithFeatures(),
|
||||
expectedConfig: map[string]string{},
|
||||
},
|
||||
{
|
||||
enabledFeatures: []string{"A", "B", "C"},
|
||||
features: featuremgmt.WithFeatures("A", "B", "C"),
|
||||
expectedConfig: map[string]string{"GF_INSTANCE_FEATURE_TOGGLES_ENABLE": "A,B,C"},
|
||||
},
|
||||
{
|
||||
enabledFeatures: []string{"C", "B", "A"},
|
||||
features: featuremgmt.WithFeatures("C", "B", "A"),
|
||||
expectedConfig: map[string]string{"GF_INSTANCE_FEATURE_TOGGLES_ENABLE": "A,B,C"},
|
||||
},
|
||||
{
|
||||
enabledFeatures: []string{"b", "a", "c", "d"},
|
||||
features: featuremgmt.WithFeatures("b", "a", "c", "d"),
|
||||
expectedConfig: map[string]string{"GF_INSTANCE_FEATURE_TOGGLES_ENABLE": "a,b,c,d"},
|
||||
},
|
||||
}
|
||||
@ -754,7 +755,7 @@ func TestService_GetConfigMap_featureToggles(t *testing.T) {
|
||||
for _, tc := range tcs {
|
||||
s := &Service{
|
||||
cfg: &config.Cfg{
|
||||
Features: fakes.NewFakeFeatureToggles(tc.enabledFeatures...),
|
||||
Features: tc.features,
|
||||
},
|
||||
}
|
||||
require.Equal(t, tc.expectedConfig, s.GetConfigMap(context.Background(), "", nil))
|
||||
|
@ -149,11 +149,6 @@ func (fn ClientMiddlewareFunc) CreateClientMiddleware(next Client) Client {
|
||||
return fn(next)
|
||||
}
|
||||
|
||||
type FeatureToggles interface {
|
||||
IsEnabledGlobally(flag string) bool
|
||||
GetEnabled(ctx context.Context) map[string]bool
|
||||
}
|
||||
|
||||
type SignatureCalculator interface {
|
||||
Calculate(ctx context.Context, src PluginSource, plugin FoundPlugin) (Signature, error)
|
||||
}
|
||||
|
@ -574,26 +574,3 @@ func (p *FakeBackendPlugin) Kill() {
|
||||
defer p.mutex.Unlock()
|
||||
p.Running = false
|
||||
}
|
||||
|
||||
type FakeFeatureToggles struct {
|
||||
features map[string]bool
|
||||
}
|
||||
|
||||
func NewFakeFeatureToggles(features ...string) *FakeFeatureToggles {
|
||||
m := make(map[string]bool)
|
||||
for _, f := range features {
|
||||
m[f] = true
|
||||
}
|
||||
|
||||
return &FakeFeatureToggles{
|
||||
features: m,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FakeFeatureToggles) GetEnabled(_ context.Context) map[string]bool {
|
||||
return f.features
|
||||
}
|
||||
|
||||
func (f *FakeFeatureToggles) IsEnabledGlobally(feature string) bool {
|
||||
return f.features[feature]
|
||||
}
|
||||
|
@ -26,10 +26,10 @@ var (
|
||||
type Local struct {
|
||||
log log.Logger
|
||||
production bool
|
||||
features plugins.FeatureToggles
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
func NewLocalFinder(devMode bool, features plugins.FeatureToggles) *Local {
|
||||
func NewLocalFinder(devMode bool, features featuremgmt.FeatureToggles) *Local {
|
||||
return &Local{
|
||||
production: !devMode,
|
||||
log: log.New("local.finder"),
|
||||
|
@ -41,7 +41,7 @@ var SharedWithMeFolderPermission = accesscontrol.Permission{
|
||||
}
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, db db.DB, routeRegister routing.RouteRegister, cache *localcache.CacheService,
|
||||
accessControl accesscontrol.AccessControl, features *featuremgmt.FeatureManager) (*Service, error) {
|
||||
accessControl accesscontrol.AccessControl, features featuremgmt.FeatureToggles) (*Service, error) {
|
||||
service := ProvideOSSService(cfg, database.ProvideService(db), cache, features)
|
||||
|
||||
api.NewAccessControlAPI(routeRegister, accessControl, service, features).RegisterAPIEndpoints()
|
||||
@ -62,7 +62,7 @@ func ProvideService(cfg *setting.Cfg, db db.DB, routeRegister routing.RouteRegis
|
||||
return service, nil
|
||||
}
|
||||
|
||||
func ProvideOSSService(cfg *setting.Cfg, store store, cache *localcache.CacheService, features *featuremgmt.FeatureManager) *Service {
|
||||
func ProvideOSSService(cfg *setting.Cfg, store store, cache *localcache.CacheService, features featuremgmt.FeatureToggles) *Service {
|
||||
s := &Service{
|
||||
cfg: cfg,
|
||||
store: store,
|
||||
@ -93,7 +93,7 @@ type Service struct {
|
||||
cache *localcache.CacheService
|
||||
registrations accesscontrol.RegistrationList
|
||||
roles map[string]*accesscontrol.RoleDTO
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
func (s *Service) GetUsageStats(_ context.Context) map[string]any {
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func NewAccessControlAPI(router routing.RouteRegister, accesscontrol ac.AccessControl, service ac.Service,
|
||||
features *featuremgmt.FeatureManager) *AccessControlAPI {
|
||||
features featuremgmt.FeatureToggles) *AccessControlAPI {
|
||||
return &AccessControlAPI{
|
||||
RouteRegister: router,
|
||||
Service: service,
|
||||
@ -28,7 +28,7 @@ type AccessControlAPI struct {
|
||||
Service ac.Service
|
||||
AccessControl ac.AccessControl
|
||||
RouteRegister routing.RouteRegister
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
func (api *AccessControlAPI) RegisterAPIEndpoints() {
|
||||
|
@ -19,7 +19,7 @@ var _ authn.HookClient = new(Session)
|
||||
var _ authn.ContextAwareClient = new(Session)
|
||||
|
||||
func ProvideSession(cfg *setting.Cfg, sessionService auth.UserTokenService,
|
||||
features *featuremgmt.FeatureManager) *Session {
|
||||
features featuremgmt.FeatureToggles) *Session {
|
||||
return &Session{
|
||||
cfg: cfg,
|
||||
features: features,
|
||||
@ -30,7 +30,7 @@ func ProvideSession(cfg *setting.Cfg, sessionService auth.UserTokenService,
|
||||
|
||||
type Session struct {
|
||||
cfg *setting.Cfg
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
sessionService auth.UserTokenService
|
||||
log log.Logger
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func TestSession_Authenticate(t *testing.T) {
|
||||
|
||||
type fields struct {
|
||||
sessionService auth.UserTokenService
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
type args struct {
|
||||
r *authn.Request
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, tracer tracing.Tracer, features *featuremgmt.FeatureManager, authnService authn.Service,
|
||||
func ProvideService(cfg *setting.Cfg, tracer tracing.Tracer, features featuremgmt.FeatureToggles, authnService authn.Service,
|
||||
) *ContextHandler {
|
||||
return &ContextHandler{
|
||||
Cfg: cfg,
|
||||
@ -39,7 +39,7 @@ func ProvideService(cfg *setting.Cfg, tracer tracing.Tracer, features *featuremg
|
||||
type ContextHandler struct {
|
||||
Cfg *setting.Cfg
|
||||
tracer tracing.Tracer
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
authnService authn.Service
|
||||
}
|
||||
|
||||
|
@ -174,10 +174,14 @@ func (fm *FeatureManager) LookupFlag(name string) (FeatureFlag, bool) {
|
||||
|
||||
// ############# Test Functions #############
|
||||
|
||||
func WithFeatures(spec ...any) FeatureToggles {
|
||||
return WithManager(spec...)
|
||||
}
|
||||
|
||||
// WithFeatures is used to define feature toggles for testing.
|
||||
// The arguments are a list of strings that are optionally followed by a boolean value for example:
|
||||
// WithFeatures([]any{"my_feature", "other_feature"}) or WithFeatures([]any{"my_feature", true})
|
||||
func WithFeatures(spec ...any) *FeatureManager {
|
||||
func WithManager(spec ...any) *FeatureManager {
|
||||
count := len(spec)
|
||||
features := make(map[string]*FeatureFlag, count)
|
||||
enabled := make(map[string]bool, count)
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
|
||||
func TestFeatureManager(t *testing.T) {
|
||||
t.Run("check testing stubs", func(t *testing.T) {
|
||||
ft := WithFeatures("a", "b", "c")
|
||||
ft := WithManager("a", "b", "c")
|
||||
require.True(t, ft.IsEnabledGlobally("a"))
|
||||
require.True(t, ft.IsEnabledGlobally("b"))
|
||||
require.True(t, ft.IsEnabledGlobally("c"))
|
||||
@ -18,7 +18,7 @@ func TestFeatureManager(t *testing.T) {
|
||||
require.Equal(t, map[string]bool{"a": true, "b": true, "c": true}, ft.GetEnabled(context.Background()))
|
||||
|
||||
// Explicit values
|
||||
ft = WithFeatures("a", true, "b", false)
|
||||
ft = WithManager("a", true, "b", false)
|
||||
require.True(t, ft.IsEnabledGlobally("a"))
|
||||
require.False(t, ft.IsEnabledGlobally("b"))
|
||||
require.Equal(t, map[string]bool{"a": true}, ft.GetEnabled(context.Background()))
|
||||
|
@ -18,6 +18,10 @@ type FeatureToggles interface {
|
||||
// Use of global feature flags should be limited and careful as they require
|
||||
// a full server restart for a change to take place.
|
||||
IsEnabledGlobally(flag string) bool
|
||||
|
||||
// Get the enabled flags -- this *may* also include disabled flags (with value false)
|
||||
// but it is guaranteed to have the enabled ones listed
|
||||
GetEnabled(ctx context.Context) map[string]bool
|
||||
}
|
||||
|
||||
// FeatureFlagStage indicates the quality level
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestFeatureUsageStats(t *testing.T) {
|
||||
featureManagerWithAllFeatures := WithFeatures(
|
||||
featureManagerWithAllFeatures := WithManager(
|
||||
"database_metrics",
|
||||
"live-config",
|
||||
"UPPER_SNAKE_CASE",
|
||||
|
@ -587,7 +587,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
service *Service
|
||||
featuresFlag *featuremgmt.FeatureManager
|
||||
featuresFlag featuremgmt.FeatureToggles
|
||||
prefix string
|
||||
depth int
|
||||
forceDelete bool
|
||||
|
@ -33,7 +33,7 @@ type ServiceImpl struct {
|
||||
pluginStore pluginstore.Store
|
||||
pluginSettings pluginsettings.Service
|
||||
starService star.Service
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
dashboardService dashboards.DashboardService
|
||||
accesscontrolService ac.Service
|
||||
kvStore kvstore.KVStore
|
||||
@ -52,7 +52,7 @@ type NavigationAppConfig struct {
|
||||
Icon string
|
||||
}
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, accessControl ac.AccessControl, pluginStore pluginstore.Store, pluginSettings pluginsettings.Service, starService star.Service, features *featuremgmt.FeatureManager, dashboardService dashboards.DashboardService, accesscontrolService ac.Service, kvStore kvstore.KVStore, apiKeyService apikey.Service, license licensing.Licensing) navtree.Service {
|
||||
func ProvideService(cfg *setting.Cfg, accessControl ac.AccessControl, pluginStore pluginstore.Store, pluginSettings pluginsettings.Service, starService star.Service, features featuremgmt.FeatureToggles, dashboardService dashboards.DashboardService, accesscontrolService ac.Service, kvStore kvstore.KVStore, apiKeyService apikey.Service, license licensing.Licensing) navtree.Service {
|
||||
service := &ServiceImpl{
|
||||
cfg: cfg,
|
||||
log: log.New("navtree service"),
|
||||
|
@ -27,7 +27,7 @@ func NewCachingMiddleware(cachingService caching.CachingService) plugins.ClientM
|
||||
|
||||
// NewCachingMiddlewareWithFeatureManager creates a new plugins.ClientMiddleware that will
|
||||
// attempt to read and write query results to the cache with a feature manager
|
||||
func NewCachingMiddlewareWithFeatureManager(cachingService caching.CachingService, features *featuremgmt.FeatureManager) plugins.ClientMiddleware {
|
||||
func NewCachingMiddlewareWithFeatureManager(cachingService caching.CachingService, features featuremgmt.FeatureToggles) plugins.ClientMiddleware {
|
||||
log := log.New("caching_middleware")
|
||||
if err := prometheus.Register(QueryCachingRequestHistogram); err != nil {
|
||||
log.Error("Error registering prometheus collector 'QueryRequestHistogram'", "error", err)
|
||||
@ -49,7 +49,7 @@ type CachingMiddleware struct {
|
||||
next plugins.Client
|
||||
caching caching.CachingService
|
||||
log log.Logger
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
// QueryData receives a data request and attempts to access results already stored in the cache for that request.
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, features *featuremgmt.FeatureManager) (*pCfg.Cfg, error) {
|
||||
func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, features featuremgmt.FeatureToggles) (*pCfg.Cfg, error) {
|
||||
plugins := settingProvider.Section("plugins")
|
||||
allowedUnsigned := grafanaCfg.PluginsAllowUnsigned
|
||||
if len(plugins.KeyValue("allow_loading_unsigned_plugins").Value()) > 0 {
|
||||
|
@ -507,7 +507,7 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
|
||||
|
||||
t.Run("Load a plugin with oauth client registration", func(t *testing.T) {
|
||||
cfg := &config.Cfg{
|
||||
Features: fakes.NewFakeFeatureToggles(featuremgmt.FlagExternalServiceAuth),
|
||||
Features: featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAuth),
|
||||
PluginsAllowUnsigned: []string{"grafana-test-datasource"},
|
||||
}
|
||||
pluginPaths := []string{filepath.Join(testDataDir(t), "oauth-external-registration")}
|
||||
@ -608,7 +608,7 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
|
||||
|
||||
t.Run("Load a plugin with service account registration", func(t *testing.T) {
|
||||
cfg := &config.Cfg{
|
||||
Features: fakes.NewFakeFeatureToggles(featuremgmt.FlagExternalServiceAuth),
|
||||
Features: featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAuth),
|
||||
PluginsAllowUnsigned: []string{"grafana-test-datasource"},
|
||||
}
|
||||
pluginPaths := []string{filepath.Join(testDataDir(t), "external-registration")}
|
||||
|
@ -3,12 +3,13 @@ package pipeline
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/log"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSkipPlugins(t *testing.T) {
|
||||
|
@ -27,7 +27,7 @@ type Api struct {
|
||||
|
||||
accessControl accesscontrol.AccessControl
|
||||
cfg *setting.Cfg
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
log log.Logger
|
||||
routeRegister routing.RouteRegister
|
||||
}
|
||||
@ -36,7 +36,7 @@ func ProvideApi(
|
||||
pd publicdashboards.Service,
|
||||
rr routing.RouteRegister,
|
||||
ac accesscontrol.AccessControl,
|
||||
features *featuremgmt.FeatureManager,
|
||||
features featuremgmt.FeatureToggles,
|
||||
md publicdashboards.Middleware,
|
||||
cfg *setting.Cfg,
|
||||
) *Api {
|
||||
@ -297,7 +297,7 @@ func (api *Api) DeletePublicDashboard(c *contextmodel.ReqContext) response.Respo
|
||||
}
|
||||
|
||||
// Copied from pkg/api/metrics.go
|
||||
func toJsonStreamingResponse(ctx context.Context, features *featuremgmt.FeatureManager, qdr *backend.QueryDataResponse) response.Response {
|
||||
func toJsonStreamingResponse(ctx context.Context, features featuremgmt.FeatureToggles, qdr *backend.QueryDataResponse) response.Response {
|
||||
statusWhenError := http.StatusBadRequest
|
||||
if features.IsEnabled(ctx, featuremgmt.FlagDatasourceQueryMultiStatus) {
|
||||
statusWhenError = http.StatusMultiStatus
|
||||
|
@ -155,6 +155,10 @@ func (f fakeFeatureToggles) IsEnabled(ctx context.Context, feature string) bool
|
||||
return f.returnValue
|
||||
}
|
||||
|
||||
func (f fakeFeatureToggles) GetEnabled(ctx context.Context) map[string]bool {
|
||||
return map[string]bool{}
|
||||
}
|
||||
|
||||
// Fake grpc secrets plugin impl
|
||||
type fakeGRPCSecretsPlugin struct {
|
||||
kv map[Key]string
|
||||
|
@ -23,7 +23,7 @@ func SetupDisabledTestService(tb testing.TB, store secrets.Store) *SecretsServic
|
||||
return setupTestService(tb, store, featuremgmt.WithFeatures(featuremgmt.FlagDisableEnvelopeEncryption))
|
||||
}
|
||||
|
||||
func setupTestService(tb testing.TB, store secrets.Store, features *featuremgmt.FeatureManager) *SecretsService {
|
||||
func setupTestService(tb testing.TB, store secrets.Store, features featuremgmt.FeatureToggles) *SecretsService {
|
||||
tb.Helper()
|
||||
defaultKey := "SdlklWklckeLS"
|
||||
if len(setting.SecretKey) > 0 {
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
|
||||
type ExtSvcAccountsService struct {
|
||||
acSvc ac.Service
|
||||
features *featuremgmt.FeatureManager
|
||||
features featuremgmt.FeatureToggles
|
||||
logger log.Logger
|
||||
metrics *metrics
|
||||
saSvc sa.Service
|
||||
|
@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
@ -18,8 +21,6 @@ import (
|
||||
sa "github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type TestEnv struct {
|
||||
|
@ -195,7 +195,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) {
|
||||
|
||||
usr := &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}}
|
||||
|
||||
for _, features := range []*featuremgmt.FeatureManager{featuremgmt.WithFeatures(), featuremgmt.WithFeatures(featuremgmt.FlagPermissionsFilterRemoveSubquery)} {
|
||||
for _, features := range []featuremgmt.FeatureToggles{featuremgmt.WithFeatures(), featuremgmt.WithFeatures(featuremgmt.FlagPermissionsFilterRemoveSubquery)} {
|
||||
m := features.GetEnabled(context.Background())
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
@ -394,7 +394,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t
|
||||
|
||||
usr := &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer, AuthenticatedBy: login.ExtendedJWTModule, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.signedInUserPermissions)}}
|
||||
|
||||
for _, features := range []*featuremgmt.FeatureManager{featuremgmt.WithFeatures(), featuremgmt.WithFeatures(featuremgmt.FlagPermissionsFilterRemoveSubquery)} {
|
||||
for _, features := range []featuremgmt.FeatureToggles{featuremgmt.WithFeatures(), featuremgmt.WithFeatures(featuremgmt.FlagPermissionsFilterRemoveSubquery)} {
|
||||
m := features.GetEnabled(context.Background())
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
@ -545,7 +545,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) {
|
||||
})
|
||||
usr := &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(tc.permissions)}}
|
||||
|
||||
for _, features := range []*featuremgmt.FeatureManager{featuremgmt.WithFeatures(tc.features...), featuremgmt.WithFeatures(append(tc.features, featuremgmt.FlagPermissionsFilterRemoveSubquery)...)} {
|
||||
for _, features := range []featuremgmt.FeatureToggles{featuremgmt.WithFeatures(tc.features...), featuremgmt.WithFeatures(append(tc.features, featuremgmt.FlagPermissionsFilterRemoveSubquery)...)} {
|
||||
m := features.GetEnabled(context.Background())
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
@ -716,7 +716,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, features := range []*featuremgmt.FeatureManager{featuremgmt.WithFeatures(tc.features...), featuremgmt.WithFeatures(append(tc.features, featuremgmt.FlagPermissionsFilterRemoveSubquery)...)} {
|
||||
for _, features := range []featuremgmt.FeatureToggles{featuremgmt.WithFeatures(tc.features...), featuremgmt.WithFeatures(append(tc.features, featuremgmt.FlagPermissionsFilterRemoveSubquery)...)} {
|
||||
m := features.GetEnabled(context.Background())
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
|
@ -34,7 +34,7 @@ type SSOSettingsService struct {
|
||||
}
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, sqlStore db.DB, ac ac.AccessControl,
|
||||
routeRegister routing.RouteRegister, features *featuremgmt.FeatureManager,
|
||||
routeRegister routing.RouteRegister, features featuremgmt.FeatureToggles,
|
||||
secrets secrets.Service) *SSOSettingsService {
|
||||
strategies := []ssosettings.FallbackStrategy{
|
||||
strategies.NewOAuthStrategy(cfg),
|
||||
|
@ -118,22 +118,8 @@ func GetMockService(version string, rt RoundTripper) *Service {
|
||||
version: version,
|
||||
fakeRoundTripper: rt,
|
||||
},
|
||||
features: &fakeFeatureToggles{
|
||||
flags: map[string]bool{
|
||||
featuremgmt.FlagInfluxqlStreamingParser: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type fakeFeatureToggles struct {
|
||||
flags map[string]bool
|
||||
// featuremgmt.FlagInfluxqlStreamingParser: false
|
||||
features: featuremgmt.WithFeatures(),
|
||||
}
|
||||
|
||||
func (f *fakeFeatureToggles) IsEnabledGlobally(flag string) bool {
|
||||
return f.flags[flag]
|
||||
}
|
||||
|
||||
func (f *fakeFeatureToggles) IsEnabled(ctx context.Context, flag string) bool {
|
||||
return f.flags[flag]
|
||||
}
|
||||
|
Reference in New Issue
Block a user