MTFF: Allow viewers access in cloud (#114607)

* Reapply "K8s: read resource configs from API Enablement for API Builders" (#114475)

This reverts commit 4130bd9cd3.

* revert part that broke things

* FF service changes are gonna come later

* MTFF: allow viewers access to MTFF by enforcing runtime_config for custom routes

* unused var

* removed now

* pass the test, include defaults

* revert sample.ini change
This commit is contained in:
Charandas
2025-12-08 17:37:10 -08:00
committed by GitHub
parent 802e208440
commit 16f5eab786
8 changed files with 181 additions and 12 deletions
-4
View File
@@ -64,10 +64,6 @@ func NewAPIBuilder(providerType string, url *url.URL, insecure bool, caFile stri
}
func RegisterAPIService(apiregistration builder.APIRegistrar, cfg *setting.Cfg) (*APIBuilder, error) {
if !cfg.OpenFeature.APIEnabled {
return nil, nil
}
var staticEvaluator featuremgmt.StaticFlagEvaluator // No static evaluator needed for non-static provider
var err error
if cfg.OpenFeature.ProviderType == setting.StaticProviderType {
+10
View File
@@ -5,6 +5,7 @@ import (
"net"
"path/filepath"
"strconv"
"strings"
"github.com/grafana/grafana/pkg/services/apiserver/options"
"github.com/grafana/grafana/pkg/services/featuremgmt"
@@ -40,6 +41,15 @@ func applyGrafanaConfig(cfg *setting.Cfg, features featuremgmt.FeatureToggles, o
apiserverCfg := cfg.SectionWithEnvOverrides("grafana-apiserver")
runtimeConfig := apiserverCfg.Key("runtime_config").String()
runtimeConfigSplit := strings.Split(runtimeConfig, ",")
// TODO: temporary fix to allow disabling local features service and still being able to use its authz handler
if !cfg.OpenFeature.APIEnabled {
runtimeConfigSplit = append(runtimeConfigSplit, "features.grafana.app/v0alpha1=false")
}
runtimeConfig = strings.Join(runtimeConfigSplit, ",")
if runtimeConfig != "" {
if err := o.APIEnablementOptions.RuntimeConfig.Set(runtimeConfig); err != nil {
return fmt.Errorf("failed to set runtime config: %w", err)
+144
View File
@@ -0,0 +1,144 @@
package apis
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/tests/testinfra"
"github.com/grafana/grafana/pkg/util/testutil"
)
const pluginsDiscoveryJSON = `[
{
"version": "v0alpha1",
"freshness": "Current",
"resources": [
{
"resource": "pluginmetas",
"responseKind": {
"group": "",
"kind": "PluginMeta",
"version": ""
},
"scope": "Namespaced",
"singularResource": "pluginmeta",
"subresources": [
{
"responseKind": {
"group": "",
"kind": "PluginMeta",
"version": ""
},
"subresource": "status",
"verbs": [
"get",
"patch",
"update"
]
}
],
"verbs": [
"get",
"list"
]
},
{
"resource": "plugins",
"responseKind": {
"group": "",
"kind": "Plugin",
"version": ""
},
"scope": "Namespaced",
"singularResource": "plugins",
"subresources": [
{
"responseKind": {
"group": "",
"kind": "Plugin",
"version": ""
},
"subresource": "status",
"verbs": [
"get",
"patch",
"update"
]
}
],
"verbs": [
"create",
"delete",
"deletecollection",
"get",
"list",
"patch",
"update",
"watch"
]
}
]
}
]`
func setupHelper(t *testing.T, openFeatureAPIEnabled bool) *K8sTestHelper {
t.Helper()
helper := NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: true,
DisableAnonymous: true,
APIServerRuntimeConfig: "plugins.grafana.app/v0alpha1=true",
OpenFeatureAPIEnabled: openFeatureAPIEnabled,
})
t.Cleanup(func() { helper.Shutdown() })
return helper
}
func TestIntegrationAPIServerRuntimeConfig(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
t.Run("discovery with openfeature api enabled", func(t *testing.T) {
helper := setupHelper(t, true)
disco, err := helper.GetGroupVersionInfoJSON("features.grafana.app")
require.NoError(t, err)
require.JSONEq(t, `[
{
"freshness": "Current",
"resources": [
{
"resource": "noop",
"responseKind": {
"group": "",
"kind": "Status",
"version": ""
},
"scope": "Namespaced",
"singularResource": "noop",
"verbs": [
"get"
]
}
],
"version": "v0alpha1"
}
]`, disco)
// plugins should still be discoverable
disco, err = helper.GetGroupVersionInfoJSON("plugins.grafana.app")
require.NoError(t, err)
require.JSONEq(t, pluginsDiscoveryJSON, disco)
require.NoError(t, err)
})
t.Run("discovery with openfeature api false", func(t *testing.T) {
helper := setupHelper(t, false)
_, err := helper.GetGroupVersionInfoJSON("features.grafana.app")
require.Error(t, err, "expected error when openfeature api is disabled")
// plugins should still be discoverable
disco, err := helper.GetGroupVersionInfoJSON("plugins.grafana.app")
require.NoError(t, err)
require.JSONEq(t, pluginsDiscoveryJSON, disco)
require.NoError(t, err)
})
}
+4 -2
View File
@@ -22,9 +22,11 @@ func TestIntegrationFeatures(t *testing.T) {
// Enable a random flag -- check that it is reported as enabled
flag := featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs
// the test below tests using enable_api = true, without that, the runtime_config has been instructed to skip the API
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: true,
DisableAnonymous: false, // allow anon user
OpenFeatureAPIEnabled: true,
AppModeProduction: true,
DisableAnonymous: false, // allow anon user
EnableFeatureToggles: []string{
flag, // used in test below
},
+3 -4
View File
@@ -792,7 +792,7 @@ func (c *K8sTestHelper) NewDiscoveryClient() *discovery.DiscoveryClient {
return client
}
func (c *K8sTestHelper) GetGroupVersionInfoJSON(group string) string {
func (c *K8sTestHelper) GetGroupVersionInfoJSON(group string) (string, error) {
c.t.Helper()
disco := c.NewDiscoveryClient()
@@ -823,12 +823,11 @@ func (c *K8sTestHelper) GetGroupVersionInfoJSON(group string) string {
if item.Metadata.Name == group {
v, err := json.MarshalIndent(item.Versions, "", " ")
require.NoError(c.t, err)
return string(v)
return string(v), nil
}
}
require.Failf(c.t, "could not find discovery info for: %s", group)
return ""
return "", goerrors.New("could not find discovery info for: " + group)
}
func (c *K8sTestHelper) CreateDS(cmd *datasources.AddDataSourceCommand) *datasources.DataSource {
+2 -1
View File
@@ -50,7 +50,8 @@ func TestIntegrationPlaylist(t *testing.T) {
}))
// The accepted verbs will change when dual write is enabled
disco := h.GetGroupVersionInfoJSON("playlist.grafana.app")
disco, err := h.GetGroupVersionInfoJSON("playlist.grafana.app")
require.NoError(t, err)
// t.Logf("%s", disco)
require.JSONEq(t, `[
{
+2 -1
View File
@@ -13,7 +13,8 @@ func TestIntegrationPluginsIntegrationDiscovery(t *testing.T) {
t.Run("discovery", func(t *testing.T) {
helper := setupHelper(t)
disco := helper.GetGroupVersionInfoJSON("plugins.grafana.app")
disco, err := helper.GetGroupVersionInfoJSON("plugins.grafana.app")
require.NoError(t, err)
require.JSONEq(t, `[
{
"version": "v0alpha1",
+16
View File
@@ -316,6 +316,21 @@ func CreateGrafDir(t *testing.T, opts GrafanaOpts) (string, string) {
_, err = serverSect.NewKey("static_root_path", publicDir)
require.NoError(t, err)
openFeatureSect, err := cfg.NewSection("feature_toggles.openfeature")
require.NoError(t, err)
_, err = openFeatureSect.NewKey("enable_api", strconv.FormatBool(opts.OpenFeatureAPIEnabled))
require.NoError(t, err)
if !opts.OpenFeatureAPIEnabled {
_, err = openFeatureSect.NewKey("provider", "static") // in practice, APIEnabled being false goes with goff type, but trying to make tests work
require.NoError(t, err)
_, err = openFeatureSect.NewKey("targetingKey", "grafana")
require.NoError(t, err)
// so staticFlags can be provided to static provider
_, err := cfg.NewSection("feature_toggles")
require.NoError(t, err)
}
anonSect, err := cfg.NewSection("auth.anonymous")
require.NoError(t, err)
_, err = anonSect.NewKey("enabled", "true")
@@ -654,6 +669,7 @@ type GrafanaOpts struct {
DisableDBCleanup bool
DisableDataMigrations bool
SecretsManagerEnableDBMigrations bool
OpenFeatureAPIEnabled bool
// Allow creating grafana dir beforehand
Dir string