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:
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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, `[
|
||||
{
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user