mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 17:22:20 +08:00
Dashboards: Preserve schema version in /api (#104213)
--------- Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
This commit is contained in:
@ -10,7 +10,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
|
||||||
dashboardv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1alpha1"
|
dashboardv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/services/apiserver"
|
"github.com/grafana/grafana/pkg/services/apiserver"
|
||||||
@ -47,7 +47,7 @@ func NewK8sClientWithFallback(
|
|||||||
) *K8sClientWithFallback {
|
) *K8sClientWithFallback {
|
||||||
newClientFunc := newK8sClientFactory(cfg, restConfigProvider, dashboardStore, userService, resourceClient, sorter, dual)
|
newClientFunc := newK8sClientFactory(cfg, restConfigProvider, dashboardStore, userService, resourceClient, sorter, dual)
|
||||||
return &K8sClientWithFallback{
|
return &K8sClientWithFallback{
|
||||||
K8sHandler: newClientFunc(context.Background(), dashboardv1.VERSION),
|
K8sHandler: newClientFunc(context.Background(), dashboardv0.VERSION),
|
||||||
newClientFunc: newClientFunc,
|
newClientFunc: newClientFunc,
|
||||||
metrics: newK8sClientMetrics(reg),
|
metrics: newK8sClientMetrics(reg),
|
||||||
log: log.New("dashboards-k8s-client"),
|
log: log.New("dashboards-k8s-client"),
|
||||||
@ -64,7 +64,7 @@ func (h *K8sClientWithFallback) Get(ctx context.Context, name string, orgID int6
|
|||||||
attribute.Bool("fallback", false),
|
attribute.Bool("fallback", false),
|
||||||
)
|
)
|
||||||
|
|
||||||
span.AddEvent("v1alpha1 Get")
|
span.AddEvent("v0alpha1 Get")
|
||||||
result, err := h.K8sHandler.Get(spanCtx, name, orgID, options, subresources...)
|
result, err := h.K8sHandler.Get(spanCtx, name, orgID, options, subresources...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracing.Error(span, err)
|
return nil, tracing.Error(span, err)
|
||||||
@ -117,7 +117,7 @@ func newK8sClientFactory(
|
|||||||
cacheMutex := &sync.RWMutex{}
|
cacheMutex := &sync.RWMutex{}
|
||||||
return func(ctx context.Context, version string) client.K8sHandler {
|
return func(ctx context.Context, version string) client.K8sHandler {
|
||||||
_, span := tracing.Start(ctx, "k8sClientFactory.GetClient",
|
_, span := tracing.Start(ctx, "k8sClientFactory.GetClient",
|
||||||
attribute.String("group", dashboardv1.GROUP),
|
attribute.String("group", dashboardv0.GROUP),
|
||||||
attribute.String("version", version),
|
attribute.String("version", version),
|
||||||
attribute.String("resource", "dashboards"),
|
attribute.String("resource", "dashboards"),
|
||||||
)
|
)
|
||||||
@ -143,7 +143,7 @@ func newK8sClientFactory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
gvr := schema.GroupVersionResource{
|
gvr := schema.GroupVersionResource{
|
||||||
Group: dashboardv1.GROUP,
|
Group: dashboardv0.GROUP,
|
||||||
Version: version,
|
Version: version,
|
||||||
Resource: "dashboards",
|
Resource: "dashboards",
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard"
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard"
|
||||||
dashboardv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
dashboardv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||||
dashboardv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1alpha1"
|
|
||||||
folderv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
folderv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||||
@ -2069,13 +2068,13 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Contex
|
|||||||
switch query.Type {
|
switch query.Type {
|
||||||
case "":
|
case "":
|
||||||
// When no type specified, search for dashboards
|
// When no type specified, search for dashboards
|
||||||
request.Options.Key, err = resource.AsResourceKey(namespace, dashboardv1.DASHBOARD_RESOURCE)
|
request.Options.Key, err = resource.AsResourceKey(namespace, dashboardv0.DASHBOARD_RESOURCE)
|
||||||
// Currently a search query is across folders and dashboards
|
// Currently a search query is across folders and dashboards
|
||||||
if err == nil {
|
if err == nil {
|
||||||
federate, err = resource.AsResourceKey(namespace, folderv1.RESOURCE)
|
federate, err = resource.AsResourceKey(namespace, folderv1.RESOURCE)
|
||||||
}
|
}
|
||||||
case searchstore.TypeDashboard, searchstore.TypeAnnotation:
|
case searchstore.TypeDashboard, searchstore.TypeAnnotation:
|
||||||
request.Options.Key, err = resource.AsResourceKey(namespace, dashboardv1.DASHBOARD_RESOURCE)
|
request.Options.Key, err = resource.AsResourceKey(namespace, dashboardv0.DASHBOARD_RESOURCE)
|
||||||
case searchstore.TypeFolder, searchstore.TypeAlertFolder:
|
case searchstore.TypeFolder, searchstore.TypeAlertFolder:
|
||||||
request.Options.Key, err = resource.AsResourceKey(namespace, folderv1.RESOURCE)
|
request.Options.Key, err = resource.AsResourceKey(namespace, folderv1.RESOURCE)
|
||||||
default:
|
default:
|
||||||
@ -2262,7 +2261,7 @@ func (dr *DashboardServiceImpl) unstructuredToLegacyDashboardWithUsers(item *uns
|
|||||||
FolderUID: obj.GetFolder(),
|
FolderUID: obj.GetFolder(),
|
||||||
Version: int(dashVersion),
|
Version: int(dashVersion),
|
||||||
Data: simplejson.NewFromAny(spec),
|
Data: simplejson.NewFromAny(spec),
|
||||||
APIVersion: strings.TrimPrefix(item.GetAPIVersion(), dashboardv1.GROUP+"/"),
|
APIVersion: strings.TrimPrefix(item.GetAPIVersion(), dashboardv0.GROUP+"/"),
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Created = obj.GetCreationTimestamp().Time
|
out.Created = obj.GetCreationTimestamp().Time
|
||||||
@ -2351,7 +2350,7 @@ func LegacySaveCommandToUnstructured(cmd *dashboards.SaveDashboardCommand, names
|
|||||||
finalObj.Object["spec"] = obj
|
finalObj.Object["spec"] = obj
|
||||||
finalObj.SetName(uid)
|
finalObj.SetName(uid)
|
||||||
finalObj.SetNamespace(namespace)
|
finalObj.SetNamespace(namespace)
|
||||||
finalObj.SetGroupVersionKind(dashboardv1.DashboardResourceInfo.GroupVersionKind())
|
finalObj.SetGroupVersionKind(dashboardv0.DashboardResourceInfo.GroupVersionKind())
|
||||||
|
|
||||||
meta, err := utils.MetaAccessor(finalObj)
|
meta, err := utils.MetaAccessor(finalObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apiserver/pkg/endpoints/request"
|
"k8s.io/apiserver/pkg/endpoints/request"
|
||||||
|
|
||||||
dashboardv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1alpha1"
|
dashboardv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
@ -543,8 +543,8 @@ func TestGetProvisionedDashboardData(t *testing.T) {
|
|||||||
k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
|
k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
|
||||||
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.Unstructured{
|
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": dashboardv1.DashboardResourceInfo.GroupVersion().String(),
|
"apiVersion": dashboardv0.DashboardResourceInfo.GroupVersion().String(),
|
||||||
"kind": dashboardv1.DashboardResourceInfo.GroupVersionKind().Kind,
|
"kind": dashboardv0.DashboardResourceInfo.GroupVersionKind().Kind,
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "uid",
|
"name": "uid",
|
||||||
"labels": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
@ -649,8 +649,8 @@ func TestGetProvisionedDashboardDataByDashboardID(t *testing.T) {
|
|||||||
provisioningTimestamp := int64(1234567)
|
provisioningTimestamp := int64(1234567)
|
||||||
k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
|
k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
|
||||||
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.Unstructured{Object: map[string]interface{}{
|
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.Unstructured{Object: map[string]interface{}{
|
||||||
"apiVersion": dashboardv1.DashboardResourceInfo.GroupVersion().String(),
|
"apiVersion": dashboardv0.DashboardResourceInfo.GroupVersion().String(),
|
||||||
"kind": dashboardv1.DashboardResourceInfo.GroupVersionKind().Kind,
|
"kind": dashboardv0.DashboardResourceInfo.GroupVersionKind().Kind,
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "uid",
|
"name": "uid",
|
||||||
"labels": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
@ -743,8 +743,8 @@ func TestGetProvisionedDashboardDataByDashboardUID(t *testing.T) {
|
|||||||
provisioningTimestamp := int64(1234567)
|
provisioningTimestamp := int64(1234567)
|
||||||
k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
|
k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
|
||||||
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.Unstructured{Object: map[string]interface{}{
|
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.Unstructured{Object: map[string]interface{}{
|
||||||
"apiVersion": dashboardv1.DashboardResourceInfo.GroupVersion().String(),
|
"apiVersion": dashboardv0.DashboardResourceInfo.GroupVersion().String(),
|
||||||
"kind": dashboardv1.DashboardResourceInfo.GroupVersionKind().Kind,
|
"kind": dashboardv0.DashboardResourceInfo.GroupVersionKind().Kind,
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "uid",
|
"name": "uid",
|
||||||
"labels": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
@ -976,8 +976,8 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) {
|
|||||||
k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
|
k8sCliMock.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
|
||||||
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.Unstructured{
|
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": dashboardv1.DashboardResourceInfo.GroupVersion().String(),
|
"apiVersion": dashboardv0.DashboardResourceInfo.GroupVersion().String(),
|
||||||
"kind": dashboardv1.DashboardResourceInfo.GroupVersionKind().Kind,
|
"kind": dashboardv0.DashboardResourceInfo.GroupVersionKind().Kind,
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "uid",
|
"name": "uid",
|
||||||
"labels": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
@ -1121,7 +1121,7 @@ func TestUnprovisionDashboard(t *testing.T) {
|
|||||||
}}
|
}}
|
||||||
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(dash, nil)
|
k8sCliMock.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(dash, nil)
|
||||||
dashWithoutAnnotations := &unstructured.Unstructured{Object: map[string]any{
|
dashWithoutAnnotations := &unstructured.Unstructured{Object: map[string]any{
|
||||||
"apiVersion": dashboardv1.APIVERSION,
|
"apiVersion": dashboardv0.APIVERSION,
|
||||||
"kind": "Dashboard",
|
"kind": "Dashboard",
|
||||||
"metadata": map[string]any{
|
"metadata": map[string]any{
|
||||||
"name": "uid",
|
"name": "uid",
|
||||||
@ -2502,7 +2502,7 @@ func TestSetDefaultPermissionsAfterCreate(t *testing.T) {
|
|||||||
|
|
||||||
// Create test object
|
// Create test object
|
||||||
key := &resource.ResourceKey{Group: "dashboard.grafana.app", Resource: "dashboards", Name: "test", Namespace: "default"}
|
key := &resource.ResourceKey{Group: "dashboard.grafana.app", Resource: "dashboards", Name: "test", Namespace: "default"}
|
||||||
obj := &dashboardv1.Dashboard{
|
obj := &dashboardv0.Dashboard{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
APIVersion: "dashboard.grafana.app/v0alpha1",
|
APIVersion: "dashboard.grafana.app/v0alpha1",
|
||||||
},
|
},
|
||||||
@ -2857,8 +2857,8 @@ func TestK8sDashboardCleanupJob(t *testing.T) {
|
|||||||
func createTestUnstructuredDashboard(uid, title string, resourceVersion string) unstructured.Unstructured {
|
func createTestUnstructuredDashboard(uid, title string, resourceVersion string) unstructured.Unstructured {
|
||||||
return unstructured.Unstructured{
|
return unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": dashboardv1.DashboardResourceInfo.GroupVersion().String(),
|
"apiVersion": dashboardv0.DashboardResourceInfo.GroupVersion().String(),
|
||||||
"kind": dashboardv1.DashboardResourceInfo.GroupVersionKind().Kind,
|
"kind": dashboardv0.DashboardResourceInfo.GroupVersionKind().Kind,
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": uid,
|
"name": uid,
|
||||||
"deletionTimestamp": "2023-01-01T00:00:00Z",
|
"deletionTimestamp": "2023-01-01T00:00:00Z",
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
|
||||||
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1alpha1"
|
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
@ -55,7 +55,7 @@ func ProvideService(cfg *setting.Cfg, db db.DB, dashboardService dashboards.Dash
|
|||||||
k8sclient: client.NewK8sHandler(
|
k8sclient: client.NewK8sHandler(
|
||||||
dual,
|
dual,
|
||||||
request.GetNamespaceMapper(cfg),
|
request.GetNamespaceMapper(cfg),
|
||||||
dashv1.DashboardResourceInfo.GroupVersionResource(),
|
dashv0.DashboardResourceInfo.GroupVersionResource(),
|
||||||
restConfigProvider.GetRestConfig,
|
restConfigProvider.GetRestConfig,
|
||||||
dashboardStore,
|
dashboardStore,
|
||||||
userService,
|
userService,
|
||||||
|
@ -340,6 +340,14 @@ func TestIntegrationCreateK8s(t *testing.T) {
|
|||||||
testCreate(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders})
|
testCreate(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPreserveSchemaVersion(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test")
|
||||||
|
}
|
||||||
|
|
||||||
|
testPreserveSchemaVersion(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders})
|
||||||
|
}
|
||||||
|
|
||||||
func testCreate(t *testing.T, featureToggles []string) {
|
func testCreate(t *testing.T, featureToggles []string) {
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
@ -499,3 +507,105 @@ func createFolder(t *testing.T, grafanaListedAddr string, title string) *dtos.Fo
|
|||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func intPtr(n int) *int {
|
||||||
|
return &n
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPreserveSchemaVersion(t *testing.T, featureToggles []string) {
|
||||||
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
|
DisableAnonymous: true,
|
||||||
|
EnableFeatureToggles: featureToggles,
|
||||||
|
})
|
||||||
|
|
||||||
|
grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path)
|
||||||
|
store, cfg := env.SQLStore, env.Cfg
|
||||||
|
|
||||||
|
createUser(t, store, cfg, user.CreateUserCommand{
|
||||||
|
DefaultOrgRole: string(org.RoleAdmin),
|
||||||
|
Password: "admin",
|
||||||
|
Login: "admin",
|
||||||
|
})
|
||||||
|
|
||||||
|
schemaVersions := []*int{intPtr(1), intPtr(36), intPtr(40), nil}
|
||||||
|
for _, schemaVersion := range schemaVersions {
|
||||||
|
var title string
|
||||||
|
if schemaVersion == nil {
|
||||||
|
title = "save dashboard with no schemaVersion"
|
||||||
|
} else {
|
||||||
|
title = fmt.Sprintf("save dashboard with schemaVersion %d", *schemaVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(title, func(t *testing.T) {
|
||||||
|
// Create dashboard JSON with specified schema version
|
||||||
|
var dashboardJSON string
|
||||||
|
if schemaVersion != nil {
|
||||||
|
dashboardJSON = fmt.Sprintf(`{"title":"Schema Version Test", "schemaVersion": %d}`, *schemaVersion)
|
||||||
|
} else {
|
||||||
|
dashboardJSON = `{"title":"Schema Version Test"}`
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboardData, err := simplejson.NewJson([]byte(dashboardJSON))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Save the dashboard via API
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err = json.NewEncoder(buf).Encode(dashboards.SaveDashboardCommand{
|
||||||
|
Dashboard: dashboardData,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
url := fmt.Sprintf("http://admin:admin@%s/api/dashboards/db", grafanaListedAddr)
|
||||||
|
// nolint:gosec
|
||||||
|
resp, err := http.Post(url, "application/json", buf)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := resp.Body.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get dashboard UID from response
|
||||||
|
b, err := io.ReadAll(resp.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
var saveResp struct {
|
||||||
|
UID string `json:"uid"`
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(b, &saveResp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, saveResp.UID)
|
||||||
|
|
||||||
|
getDashURL := fmt.Sprintf("http://admin:admin@%s/api/dashboards/uid/%s", grafanaListedAddr, saveResp.UID)
|
||||||
|
// nolint:gosec
|
||||||
|
getResp, err := http.Get(getDashURL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, http.StatusOK, getResp.StatusCode)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := getResp.Body.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parse response and check if schema version is preserved
|
||||||
|
dashBody, err := io.ReadAll(getResp.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var dashResp struct {
|
||||||
|
Dashboard *simplejson.Json `json:"dashboard"`
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(dashBody, &dashResp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actualSchemaVersion := dashResp.Dashboard.Get("schemaVersion")
|
||||||
|
if schemaVersion != nil {
|
||||||
|
// Check if schemaVersion is preserved (not migrated to latest)
|
||||||
|
actualVersion := actualSchemaVersion.MustInt()
|
||||||
|
require.Equal(t, *schemaVersion, actualVersion,
|
||||||
|
"Dashboard schemaVersion should not be automatically changed when saved through /api/dashboards/db")
|
||||||
|
} else {
|
||||||
|
actualVersion, err := actualSchemaVersion.Int()
|
||||||
|
s, _ := dashResp.Dashboard.EncodePretty()
|
||||||
|
require.Error(t, err, fmt.Sprintf("Dashboard schemaVersion should not be automatically populated when saved through /api/dashboards/db, was %d. %s", actualVersion, string(s)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -350,7 +350,7 @@ func TestIntegrationLegacySupport(t *testing.T) {
|
|||||||
Path: "/api/dashboards/uid/test-v1",
|
Path: "/api/dashboards/uid/test-v1",
|
||||||
}, &dtos.DashboardFullWithMeta{})
|
}, &dtos.DashboardFullWithMeta{})
|
||||||
require.Equal(t, 200, rsp.Response.StatusCode)
|
require.Equal(t, 200, rsp.Response.StatusCode)
|
||||||
require.Equal(t, "v1alpha1", rsp.Result.Meta.APIVersion)
|
require.Equal(t, "v0alpha1", rsp.Result.Meta.APIVersion) // v0alpha1 is used as the default version for /api
|
||||||
|
|
||||||
// V2 should send a not acceptable
|
// V2 should send a not acceptable
|
||||||
rsp = apis.DoRequest(helper, apis.RequestParams{
|
rsp = apis.DoRequest(helper, apis.RequestParams{
|
||||||
|
Reference in New Issue
Block a user