Storage: Read desired mode from config instead of feature flags (#88353)

* Read desired mode from config
* Update playlist integration tests
* Add mode 1 playlist integration tests
* Add mode 0 dual writing to playlist integration tests
* Add documentation for the different dual writing modes
This commit is contained in:
Arati R
2024-05-31 19:29:59 +02:00
committed by GitHub
parent d3fa52a730
commit 36f42853dd
25 changed files with 300 additions and 72 deletions
+130 -7
View File
@@ -14,6 +14,8 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
playlistv0alpha1 "github.com/grafana/grafana/pkg/apis/playlist/v0alpha1"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/tests/apis"
@@ -85,20 +87,51 @@ func TestIntegrationPlaylist(t *testing.T) {
}))
})
// #TODO add equivalent tests for the other modes
t.Run("with dual write (file)", func(t *testing.T) {
t.Run("with dual write (file, mode 0)", func(t *testing.T) {
doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: true,
DisableAnonymous: true,
APIServerStorageType: "file", // write the files to disk
EnableFeatureToggles: []string{
featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
featuremgmt.FlagDualWritePlaylistsMode2,
},
DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode0,
},
}))
})
t.Run("with dual write (unified storage)", func(t *testing.T) {
// #TODO Enable this test once we have fixed dual writing mode 1 behavior
// Do_CRUD_via_k8s_(and_check_that_legacy_api_still_works) breaks
// t.Run("with dual write (file, mode 1)", func(t *testing.T) {
// doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
// AppModeProduction: true,
// DisableAnonymous: true,
// APIServerStorageType: "file", // write the files to disk
// EnableFeatureToggles: []string{
// featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
// },
// DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
// playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode1,
// },
// }))
// })
t.Run("with dual write (file, mode 2)", func(t *testing.T) {
doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: true,
DisableAnonymous: true,
APIServerStorageType: "file", // write the files to disk
EnableFeatureToggles: []string{
featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
},
DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode2,
},
}))
})
t.Run("with dual write (unified storage, mode 0)", func(t *testing.T) {
doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: false, // required for unified storage
DisableAnonymous: true,
@@ -106,12 +139,46 @@ func TestIntegrationPlaylist(t *testing.T) {
EnableFeatureToggles: []string{
featuremgmt.FlagUnifiedStorage,
featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
featuremgmt.FlagDualWritePlaylistsMode2,
},
DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode0,
},
}))
})
t.Run("with dual write (etcd)", func(t *testing.T) {
// #TODO Enable this test once we have fixed dual writing mode 1 behavior
// Do_CRUD_via_k8s_(and_check_that_legacy_api_still_works) breaks
// t.Run("with dual write (unified storage, mode 1)", func(t *testing.T) {
// doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
// AppModeProduction: false, // required for unified storage
// DisableAnonymous: true,
// APIServerStorageType: "unified", // use the entity api tables
// EnableFeatureToggles: []string{
// featuremgmt.FlagUnifiedStorage,
// featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
// },
// DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
// playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode1,
// },
// }))
// })
t.Run("with dual write (unified storage, mode 2)", func(t *testing.T) {
doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: false, // required for unified storage
DisableAnonymous: true,
APIServerStorageType: "unified", // use the entity api tables
EnableFeatureToggles: []string{
featuremgmt.FlagUnifiedStorage,
featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
},
DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode2,
},
}))
})
t.Run("with dual write (etcd, mode 0)", func(t *testing.T) {
// NOTE: running local etcd, that will be wiped clean!
t.Skip("local etcd testing")
@@ -121,7 +188,63 @@ func TestIntegrationPlaylist(t *testing.T) {
APIServerStorageType: "etcd", // requires etcd running on localhost:2379
EnableFeatureToggles: []string{
featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
featuremgmt.FlagDualWritePlaylistsMode2,
},
DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode0,
},
})
// Clear the collection before starting (etcd)
client := helper.GetResourceClient(apis.ResourceClientArgs{
User: helper.Org1.Admin,
GVR: gvr,
})
err := client.Resource.DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})
require.NoError(t, err)
doPlaylistTests(t, helper)
})
t.Run("with dual write (etcd, mode 1)", func(t *testing.T) {
// NOTE: running local etcd, that will be wiped clean!
t.Skip("local etcd testing")
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: true,
DisableAnonymous: true,
APIServerStorageType: "etcd", // requires etcd running on localhost:2379
EnableFeatureToggles: []string{
featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
},
DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode1,
},
})
// Clear the collection before starting (etcd)
client := helper.GetResourceClient(apis.ResourceClientArgs{
User: helper.Org1.Admin,
GVR: gvr,
})
err := client.Resource.DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})
require.NoError(t, err)
doPlaylistTests(t, helper)
})
t.Run("with dual write (etcd, mode 2)", func(t *testing.T) {
// NOTE: running local etcd, that will be wiped clean!
t.Skip("local etcd testing")
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: true,
DisableAnonymous: true,
APIServerStorageType: "etcd", // requires etcd running on localhost:2379
EnableFeatureToggles: []string{
featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
},
DualWriterDesiredModes: map[string]grafanarest.DualWriterMode{
playlistv0alpha1.GROUPRESOURCE: grafanarest.Mode2,
},
})
+11
View File
@@ -17,6 +17,7 @@ import (
"gopkg.in/ini.v1"
"github.com/grafana/grafana/pkg/api"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
"github.com/grafana/grafana/pkg/extensions"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/fs"
@@ -384,6 +385,15 @@ func CreateGrafDir(t *testing.T, opts ...GrafanaOpts) (string, string) {
_, err = grafanaComSection.NewKey("api_url", o.GrafanaComAPIURL)
require.NoError(t, err)
}
if o.DualWriterDesiredModes != nil {
unifiedStorageMode, err := getOrCreateSection("unified_storage_mode")
require.NoError(t, err)
for k, v := range o.DualWriterDesiredModes {
_, err = unifiedStorageMode.NewKey(k, fmt.Sprint(v))
require.NoError(t, err)
}
}
}
logSection, err := getOrCreateSection("database")
require.NoError(t, err)
@@ -431,6 +441,7 @@ type GrafanaOpts struct {
QueryRetries int64
APIServerStorageType string
GrafanaComAPIURL string
DualWriterDesiredModes map[string]grafanarest.DualWriterMode
}
func CreateUser(t *testing.T, store db.DB, cfg *setting.Cfg, cmd user.CreateUserCommand) *user.User {