Dashboards: Add Dashboard Schema validation (2) (#103844)
* Activate schema validation and align underlying systems * update to save as v0 if not the right schema version * Resolve merge conflicts * Move RequireApiErrorStatus to tests package * Add mutation tests * Fix lint * Only do min version check if dashboard is v1 * Fix lint and disable provisioning test * Revert provisioning changes * Revert more tests and add schema test * Reran gen * SQL Dashboard save * Adjust APIVERSION * Fixed mutation test * Add logging on downgrade --------- Co-authored-by: Marco de Abreu <18629099+marcoabreu@users.noreply.github.com> Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
This commit is contained in:
co-authored by
Marco de Abreu
Stephanie Hingtgen
parent
07a225649d
commit
c47ab101d1
@@ -7,7 +7,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
dashboardv0alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||
dashboardv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1alpha1"
|
||||
dashboardv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
folders "github.com/grafana/grafana/pkg/apis/folder/v1"
|
||||
"github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@@ -219,19 +221,88 @@ func runDashboardValidationTests(t *testing.T, ctx TestContext) {
|
||||
t.Run("Dashboard schema validations", func(t *testing.T) {
|
||||
// Test invalid dashboard schema
|
||||
t.Run("reject dashboard with invalid schema", func(t *testing.T) {
|
||||
dashObj := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": dashboardv1.DashboardResourceInfo.GroupVersion().String(),
|
||||
"kind": dashboardv1.DashboardResourceInfo.GroupVersionKind().Kind,
|
||||
"metadata": map[string]interface{}{
|
||||
"generateName": "test-",
|
||||
testCases := []struct {
|
||||
name string
|
||||
resourceInfo utils.ResourceInfo
|
||||
expectSpecErr bool
|
||||
testObject *unstructured.Unstructured
|
||||
}{
|
||||
{
|
||||
name: "v0alpha1 dashboard with wrong spec should not throw on v0",
|
||||
resourceInfo: dashboardv0alpha1.DashboardResourceInfo,
|
||||
expectSpecErr: false,
|
||||
testObject: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": dashboardv0alpha1.DashboardResourceInfo.TypeMeta().APIVersion,
|
||||
"kind": "Dashboard",
|
||||
"metadata": map[string]interface{}{
|
||||
"generateName": "test-",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"title": "Dashboard Title",
|
||||
"schemaVersion": 41,
|
||||
"editable": "elephant",
|
||||
"time": 9000,
|
||||
"uid": strings.Repeat("a", 100),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v1 dashboard with wrong spec should throw on v1",
|
||||
resourceInfo: dashboardv1.DashboardResourceInfo,
|
||||
expectSpecErr: true,
|
||||
testObject: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": dashboardv1.DashboardResourceInfo.TypeMeta().APIVersion,
|
||||
"kind": "Dashboard",
|
||||
"metadata": map[string]interface{}{
|
||||
"generateName": "test-",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"title": "Dashboard Title",
|
||||
"schemaVersion": 41,
|
||||
"editable": "elephant",
|
||||
"time": 9000,
|
||||
"uid": strings.Repeat("a", 100),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v2alpha1 dashboard with correct spec should not throw on v2",
|
||||
resourceInfo: dashboardv2alpha1.DashboardResourceInfo,
|
||||
expectSpecErr: false,
|
||||
testObject: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": dashboardv2alpha1.DashboardResourceInfo.TypeMeta().APIVersion,
|
||||
"kind": "Dashboard",
|
||||
"metadata": map[string]interface{}{
|
||||
"generateName": "test-",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"title": "Dashboard Title",
|
||||
"description": "valid description",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Missing spec
|
||||
},
|
||||
}
|
||||
|
||||
_, err := adminClient.Resource.Create(context.Background(), dashObj, v1.CreateOptions{})
|
||||
require.Error(t, err)
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
resourceClient := getResourceClient(t, ctx.Helper, ctx.AdminUser, tc.resourceInfo.GroupVersionResource())
|
||||
createdDashboard, err := resourceClient.Resource.Create(context.Background(), tc.testObject, v1.CreateOptions{})
|
||||
if tc.expectSpecErr {
|
||||
ctx.Helper.RequireApiErrorStatus(err, v1.StatusReasonInvalid, http.StatusUnprocessableEntity)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, createdDashboard)
|
||||
err = resourceClient.Resource.Delete(context.Background(), createdDashboard.GetName(), v1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -683,20 +754,12 @@ func createTestContext(t *testing.T, helper *apis.K8sTestHelper, orgUsers apis.O
|
||||
|
||||
// getDashboardGVR returns the dashboard GroupVersionResource
|
||||
func getDashboardGVR() schema.GroupVersionResource {
|
||||
return schema.GroupVersionResource{
|
||||
Group: dashboardv1.DashboardResourceInfo.GroupVersion().Group,
|
||||
Version: dashboardv1.DashboardResourceInfo.GroupVersion().Version,
|
||||
Resource: dashboardv1.DashboardResourceInfo.GetName(),
|
||||
}
|
||||
return dashboardv1.DashboardResourceInfo.GroupVersionResource()
|
||||
}
|
||||
|
||||
// getFolderGVR returns the folder GroupVersionResource
|
||||
func getFolderGVR() schema.GroupVersionResource {
|
||||
return schema.GroupVersionResource{
|
||||
Group: folders.FolderResourceInfo.GroupVersion().Group,
|
||||
Version: folders.FolderResourceInfo.GroupVersion().Version,
|
||||
Resource: folders.FolderResourceInfo.GetName(),
|
||||
}
|
||||
return folders.FolderResourceInfo.GroupVersionResource()
|
||||
}
|
||||
|
||||
// Get a resource client for the specified user
|
||||
|
||||
Reference in New Issue
Block a user