Storage: Unified Storage based on Entity API (#71977)

* first round of entityapi updates

- quote column names and clean up insert/update queries
- replace grn with guid
- streamline table structure

fixes

streamline entity history

move EntitySummary into proto

remove EntitySummary

add guid to json

fix tests

change DB_Uuid to DB_NVarchar

fix folder test

convert interface to any

more cleanup

start entity store under grafana-apiserver dskit target

CRUD working, kind of

rough cut of wiring entity api to kube-apiserver

fake grafana user in context

add key to entity

list working

revert unnecessary changes

move entity storage files to their own package, clean up

use accessor to read/write grafana annotations

implement separate Create and Update functions

* go mod tidy

* switch from Kind to resource

* basic grpc storage server

* basic support for grpc entity store

* don't connect to database unless it's needed, pass user identity over grpc

* support getting user from k8s context, fix some mysql issues

* assign owner to snowflake dependency

* switch from ulid to uuid for guids

* cleanup, rename Search to List

* remove entityListResult

* EntityAPI: remove extra user abstraction (#79033)

* remove extra user abstraction

* add test stub (but

* move grpc context setup into client wrapper, fix lint issue

* remove unused constants

* remove custom json stuff

* basic list filtering, add todo

* change target to storage-server, allow entityStore flag in prod mode

* fix issue with Update

* EntityAPI: make test work, need to resolve expected differences (#79123)

* make test work, need to resolve expected differences

* remove the fields not supported by legacy

* sanitize out the bits legacy does not support

* sanitize out the bits legacy does not support

---------

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>

* update feature toggle generated files

* remove unused http headers

* update feature flag strategy

* devmode

* update readme

* spelling

* readme

---------

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
Dan Cech
2023-12-06 21:21:21 +01:00
committed by GitHub
parent 07915703fe
commit c4c9bfaf2e
42 changed files with 4358 additions and 2389 deletions

View File

@@ -131,6 +131,11 @@ func (c *K8sResourceClient) SanitizeJSON(v *unstructured.Unstructured) string {
if anno["grafana.app/updatedTimestamp"] != "" {
anno["grafana.app/updatedTimestamp"] = "${updatedTimestamp}"
}
// Remove annotations that are not added by legacy storage
delete(anno, "grafana.app/originTimestamp")
delete(anno, "grafana.app/createdBy")
delete(anno, "grafana.app/updatedBy")
deep.SetAnnotations(anno)
copy := deep.Object
meta, ok := copy["metadata"].(map[string]any)

View File

@@ -94,6 +94,19 @@ func TestPlaylist(t *testing.T) {
}))
})
t.Run("with dual write (unified storage)", 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.FlagGrafanaAPIServer,
featuremgmt.FlagKubernetesPlaylists, // Required so that legacy calls are also written
},
}))
})
t.Run("with dual write (etcd)", func(t *testing.T) {
// NOTE: running local etcd, that will be wiped clean!
t.Skip("local etcd testing")
@@ -271,6 +284,7 @@ func doPlaylistTests(t *testing.T, helper *apis.K8sTestHelper) *apis.K8sTestHelp
Path: "/api/playlists/" + uid,
Body: []byte(legacyPayload),
}, &playlist.PlaylistDTO{})
require.Equal(t, 200, dtoResponse.Response.StatusCode)
require.Equal(t, uid, dtoResponse.Result.Uid)
require.Equal(t, "10m", dtoResponse.Result.Interval)
@@ -280,12 +294,13 @@ func doPlaylistTests(t *testing.T, helper *apis.K8sTestHelper) *apis.K8sTestHelp
require.JSONEq(t, expectedResult, client.SanitizeJSON(found))
// Delete does not return anything
_ = apis.DoRequest(helper, apis.RequestParams{
deleteResponse := apis.DoRequest(helper, apis.RequestParams{
User: client.Args.User,
Method: http.MethodDelete,
Path: "/api/playlists/" + uid,
Body: []byte(legacyPayload),
}, &playlist.PlaylistDTO{}) // response is empty
require.Equal(t, 200, deleteResponse.Response.StatusCode)
found, err = client.Resource.Get(context.Background(), uid, metav1.GetOptions{})
statusError := helper.AsStatusError(err)