Dashboards API: v2alpha2 missing pieces (#108293)
* Dashboards API: v2alpha2 missing pieces * Fix issue with dashboard client scope for alpha versions As we now have 2 different alpha versions for v2 we need to store the clients separately. * Improve debuggability of provisioning export test - Add a helper function to print the tree structure. - Be explicit about the expected file names expected in each case. * Update pkg/registry/apis/dashboard/mutate.go * Update pkg/services/authz/zanzana/server/server.go Co-authored-by: Igor Suleymanov <radiohead@users.noreply.github.com> * Review * go lint --------- Co-authored-by: Roberto Jimenez Sanchez <roberto.jimenez@grafana.com> Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com> Co-authored-by: Igor Suleymanov <radiohead@users.noreply.github.com>
This commit is contained in:
co-authored by
Igor Suleymanov
Roberto Jimenez Sanchez
Stephanie Hingtgen
parent
eeb44c1d63
commit
d72a70d246
@@ -23,7 +23,8 @@ import (
|
||||
|
||||
dashboardV0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||
dashboardV1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
dashboardV2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
dashboardV2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
dashboardV2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -164,10 +165,10 @@ func TestIntegrationDashboardsAppV1(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrationDashboardsAppV2(t *testing.T) {
|
||||
func TestIntegrationDashboardsAppV2alpha1(t *testing.T) {
|
||||
gvr := schema.GroupVersionResource{
|
||||
Group: dashboardV2.GROUP,
|
||||
Version: dashboardV2.VERSION,
|
||||
Group: dashboardV2alpha1.GROUP,
|
||||
Version: dashboardV2alpha1.VERSION,
|
||||
Resource: "dashboards",
|
||||
}
|
||||
if testing.Short() {
|
||||
@@ -176,7 +177,33 @@ func TestIntegrationDashboardsAppV2(t *testing.T) {
|
||||
|
||||
modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5}
|
||||
for _, mode := range modes {
|
||||
t.Run(fmt.Sprintf("v1beta1 with dual writer mode %d", mode), func(t *testing.T) {
|
||||
t.Run(fmt.Sprintf("v2alpha1 with dual writer mode %d", mode), func(t *testing.T) {
|
||||
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||
DisableAnonymous: true,
|
||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||
"dashboards.dashboard.grafana.app": {
|
||||
DualWriterMode: mode,
|
||||
},
|
||||
},
|
||||
})
|
||||
runDashboardTest(t, helper, gvr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrationDashboardsAppV2alpha2(t *testing.T) {
|
||||
gvr := schema.GroupVersionResource{
|
||||
Group: dashboardV2alpha2.GROUP,
|
||||
Version: dashboardV2alpha2.VERSION,
|
||||
Resource: "dashboards",
|
||||
}
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
|
||||
modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5}
|
||||
for _, mode := range modes {
|
||||
t.Run(fmt.Sprintf("v1alpha2 with dual writer mode %d", mode), func(t *testing.T) {
|
||||
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||
DisableAnonymous: true,
|
||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||
@@ -223,7 +250,7 @@ func TestIntegrationLegacySupport(t *testing.T) {
|
||||
|
||||
clientV2 := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
GVR: dashboardV2.DashboardResourceInfo.GroupVersionResource(),
|
||||
GVR: dashboardV2alpha1.DashboardResourceInfo.GroupVersionResource(),
|
||||
})
|
||||
obj, err = clientV2.Resource.Create(ctx,
|
||||
helper.LoadYAMLOrJSONFile("testdata/dashboard-test-v2.yaml"),
|
||||
|
||||
@@ -16,7 +16,8 @@ import (
|
||||
|
||||
dashboardV0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||
dashboardV1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
dashboardV2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
dashboardV2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
dashboardV2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
|
||||
foldersV1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@@ -345,11 +346,29 @@ func runDashboardValidationTests(t *testing.T, ctx TestContext) {
|
||||
},
|
||||
{
|
||||
name: "v2alpha1 dashboard with correct spec should not throw on v2",
|
||||
resourceInfo: dashboardV2.DashboardResourceInfo,
|
||||
resourceInfo: dashboardV2alpha1.DashboardResourceInfo,
|
||||
expectSpecErr: false,
|
||||
testObject: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": dashboardV2.DashboardResourceInfo.TypeMeta().APIVersion,
|
||||
"apiVersion": dashboardV2alpha1.DashboardResourceInfo.TypeMeta().APIVersion,
|
||||
"kind": "Dashboard",
|
||||
"metadata": map[string]interface{}{
|
||||
"generateName": "test-",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"title": "Dashboard Title",
|
||||
"description": "valid description",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v2alpha2 dashboard with correct spec should not throw on v2",
|
||||
resourceInfo: dashboardV2alpha2.DashboardResourceInfo,
|
||||
expectSpecErr: false,
|
||||
testObject: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": dashboardV2alpha2.DashboardResourceInfo.TypeMeta().APIVersion,
|
||||
"kind": "Dashboard",
|
||||
"metadata": map[string]interface{}{
|
||||
"generateName": "test-",
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
apiVersion: dashboard.grafana.app/v2alpha1
|
||||
kind: Dashboard
|
||||
metadata:
|
||||
name: test-v2
|
||||
name: test-v2alpha1
|
||||
spec:
|
||||
title: Test dashboard. Created at v2
|
||||
title: Test dashboard. Created at v2alpha1
|
||||
layout:
|
||||
kind: GridLayout
|
||||
spec:
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: dashboard.grafana.app/v2alpha2
|
||||
kind: Dashboard
|
||||
metadata:
|
||||
name: test-v2alpha2
|
||||
spec:
|
||||
title: Test dashboard. Created at v2alpha2
|
||||
layout:
|
||||
kind: GridLayout
|
||||
spec:
|
||||
items: []
|
||||
@@ -21,7 +21,8 @@ import (
|
||||
|
||||
dashboardV0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||
dashboardV1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
dashboardV2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
dashboardsV2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
dashboardsV2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
|
||||
folder "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
@@ -41,15 +42,16 @@ type provisioningTestHelper struct {
|
||||
*apis.K8sTestHelper
|
||||
ProvisioningPath string
|
||||
|
||||
Repositories *apis.K8sResourceClient
|
||||
Jobs *apis.K8sResourceClient
|
||||
Folders *apis.K8sResourceClient
|
||||
DashboardsV0 *apis.K8sResourceClient
|
||||
DashboardsV1 *apis.K8sResourceClient
|
||||
DashboardsV2 *apis.K8sResourceClient
|
||||
AdminREST *rest.RESTClient
|
||||
EditorREST *rest.RESTClient
|
||||
ViewerREST *rest.RESTClient
|
||||
Repositories *apis.K8sResourceClient
|
||||
Jobs *apis.K8sResourceClient
|
||||
Folders *apis.K8sResourceClient
|
||||
DashboardsV0 *apis.K8sResourceClient
|
||||
DashboardsV1 *apis.K8sResourceClient
|
||||
DashboardsV2alpha1 *apis.K8sResourceClient
|
||||
DashboardsV2alpha2 *apis.K8sResourceClient
|
||||
AdminREST *rest.RESTClient
|
||||
EditorREST *rest.RESTClient
|
||||
ViewerREST *rest.RESTClient
|
||||
}
|
||||
|
||||
func (h *provisioningTestHelper) SyncAndWait(t *testing.T, repo string, options *provisioning.SyncJobOptions) {
|
||||
@@ -255,10 +257,15 @@ func runGrafana(t *testing.T, options ...grafanaOption) *provisioningTestHelper
|
||||
Namespace: "default", // actually org1
|
||||
GVR: dashboardV1.DashboardResourceInfo.GroupVersionResource(),
|
||||
})
|
||||
dashboardsV2 := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
dashboardsV2alpha1 := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
Namespace: "default", // actually org1
|
||||
GVR: dashboardV2.DashboardResourceInfo.GroupVersionResource(),
|
||||
GVR: dashboardsV2alpha1.DashboardResourceInfo.GroupVersionResource(),
|
||||
})
|
||||
dashboardsV2alpha2 := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
User: helper.Org1.Admin,
|
||||
Namespace: "default", // actually org1
|
||||
GVR: dashboardsV2alpha2.DashboardResourceInfo.GroupVersionResource(),
|
||||
})
|
||||
|
||||
// Repo client, but less guard rails. Useful for subresources. We'll need this later...
|
||||
@@ -289,15 +296,16 @@ func runGrafana(t *testing.T, options ...grafanaOption) *provisioningTestHelper
|
||||
ProvisioningPath: provisioningPath,
|
||||
K8sTestHelper: helper,
|
||||
|
||||
Repositories: repositories,
|
||||
AdminREST: adminClient,
|
||||
EditorREST: editorClient,
|
||||
ViewerREST: viewerClient,
|
||||
Jobs: jobs,
|
||||
Folders: folders,
|
||||
DashboardsV0: dashboardsV0,
|
||||
DashboardsV1: dashboardsV1,
|
||||
DashboardsV2: dashboardsV2,
|
||||
Repositories: repositories,
|
||||
AdminREST: adminClient,
|
||||
EditorREST: editorClient,
|
||||
ViewerREST: viewerClient,
|
||||
Jobs: jobs,
|
||||
Folders: folders,
|
||||
DashboardsV0: dashboardsV0,
|
||||
DashboardsV1: dashboardsV1,
|
||||
DashboardsV2alpha1: dashboardsV2alpha1,
|
||||
DashboardsV2alpha2: dashboardsV2alpha2,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -21,11 +22,50 @@ import (
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/extensions"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||
"github.com/grafana/grafana/pkg/tests/apis"
|
||||
)
|
||||
|
||||
// printFileTree prints the directory structure as a tree for debugging purposes
|
||||
func printFileTree(t *testing.T, rootPath string) {
|
||||
t.Helper()
|
||||
t.Logf("File tree for %s:", rootPath)
|
||||
|
||||
err := filepath.WalkDir(rootPath, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
relPath, err := filepath.Rel(rootPath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if relPath == "." {
|
||||
return nil
|
||||
}
|
||||
|
||||
depth := strings.Count(relPath, string(filepath.Separator))
|
||||
indent := strings.Repeat(" ", depth)
|
||||
|
||||
if d.IsDir() {
|
||||
t.Logf("%s├── %s/", indent, d.Name())
|
||||
} else {
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
t.Logf("%s├── %s (error reading info)", indent, d.Name())
|
||||
} else {
|
||||
t.Logf("%s├── %s (%d bytes)", indent, d.Name(), info.Size())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Logf("Error walking directory: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrationProvisioning_CreatingAndGetting(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
@@ -609,9 +649,13 @@ func TestProvisioning_ExportUnifiedToRepository(t *testing.T) {
|
||||
_, err = helper.DashboardsV1.Resource.Create(ctx, dashboard, metav1.CreateOptions{})
|
||||
require.NoError(t, err, "should be able to create v1 dashboard")
|
||||
|
||||
dashboard = helper.LoadYAMLOrJSONFile("exportunifiedtorepository/dashboard-test-v2.yaml")
|
||||
_, err = helper.DashboardsV2.Resource.Create(ctx, dashboard, metav1.CreateOptions{})
|
||||
require.NoError(t, err, "should be able to create v2 dashboard")
|
||||
dashboard = helper.LoadYAMLOrJSONFile("exportunifiedtorepository/dashboard-test-v2alpha1.yaml")
|
||||
_, err = helper.DashboardsV2alpha1.Resource.Create(ctx, dashboard, metav1.CreateOptions{})
|
||||
require.NoError(t, err, "should be able to create v2alpha1 dashboard")
|
||||
|
||||
dashboard = helper.LoadYAMLOrJSONFile("exportunifiedtorepository/dashboard-test-v2alpha2.yaml")
|
||||
_, err = helper.DashboardsV2alpha2.Resource.Create(ctx, dashboard, metav1.CreateOptions{})
|
||||
require.NoError(t, err, "should be able to create v2alpha2 dashboard")
|
||||
|
||||
// Now for the repository.
|
||||
const repo = "local-repository"
|
||||
@@ -642,15 +686,19 @@ func TestProvisioning_ExportUnifiedToRepository(t *testing.T) {
|
||||
title string
|
||||
apiVersion string
|
||||
name string
|
||||
fileName string
|
||||
}
|
||||
|
||||
printFileTree(t, helper.ProvisioningPath)
|
||||
|
||||
// Check that each file was exported with its stored version
|
||||
for _, test := range []props{
|
||||
{title: "Test dashboard. Created at v0", apiVersion: "dashboard.grafana.app/v0alpha1", name: "test-v0"},
|
||||
{title: "Test dashboard. Created at v1", apiVersion: "dashboard.grafana.app/v1beta1", name: "test-v1"},
|
||||
{title: "Test dashboard. Created at v2", apiVersion: "dashboard.grafana.app/v2alpha1", name: "test-v2"},
|
||||
{title: "Test dashboard. Created at v0", apiVersion: "dashboard.grafana.app/v0alpha1", name: "test-v0", fileName: "test-dashboard-created-at-v0.json"},
|
||||
{title: "Test dashboard. Created at v1", apiVersion: "dashboard.grafana.app/v1beta1", name: "test-v1", fileName: "test-dashboard-created-at-v1.json"},
|
||||
{title: "Test dashboard. Created at v2alpha1", apiVersion: "dashboard.grafana.app/v2alpha1", name: "test-v2alpha1", fileName: "test-dashboard-created-at-v2alpha1.json"},
|
||||
{title: "Test dashboard. Created at v2alpha2", apiVersion: "dashboard.grafana.app/v2alpha2", name: "test-v2alpha2", fileName: "test-dashboard-created-at-v2alpha2.json"},
|
||||
} {
|
||||
fpath := filepath.Join(helper.ProvisioningPath, slugify.Slugify(test.title)+".json")
|
||||
fpath := filepath.Join(helper.ProvisioningPath, test.fileName)
|
||||
//nolint:gosec // we are ok with reading files in testdata
|
||||
body, err := os.ReadFile(fpath)
|
||||
require.NoError(t, err, "exported file was not created at path %s", fpath)
|
||||
|
||||
Reference in New Issue
Block a user