Merge remote-tracking branch 'origin/main' into ds-apiserver-schema-builder
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
package templateGroup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.yaml.in/yaml/v3"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/tests/api/alerting"
|
||||
"github.com/grafana/grafana/pkg/tests/apis"
|
||||
"github.com/grafana/grafana/pkg/tests/apis/alerting/notifications/common"
|
||||
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||
"github.com/grafana/grafana/pkg/util/testutil"
|
||||
)
|
||||
|
||||
//go:embed test-data/*.*
|
||||
var testData embed.FS
|
||||
|
||||
func TestIntegrationImportedTemplates(t *testing.T) {
|
||||
testutil.SkipIntegrationTestInShortMode(t)
|
||||
|
||||
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||
EnableFeatureToggles: []string{
|
||||
featuremgmt.FlagAlertingImportAlertmanagerAPI,
|
||||
},
|
||||
})
|
||||
|
||||
client := common.NewTemplateGroupClient(t, helper.Org1.Admin)
|
||||
|
||||
cliCfg := helper.Org1.Admin.NewRestConfig()
|
||||
alertingApi := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
||||
|
||||
configYaml, err := testData.ReadFile(path.Join("test-data", "imported.yaml"))
|
||||
require.NoError(t, err)
|
||||
|
||||
identifier := "test-create-get-config"
|
||||
mergeMatchers := "_imported=true"
|
||||
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/yaml",
|
||||
"X-Grafana-Alerting-Config-Identifier": identifier,
|
||||
"X-Grafana-Alerting-Merge-Matchers": mergeMatchers,
|
||||
}
|
||||
var amConfig apimodels.AlertmanagerUserConfig
|
||||
require.NoError(t, yaml.Unmarshal(configYaml, &amConfig))
|
||||
|
||||
response := alertingApi.ConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers)
|
||||
require.Equal(t, "success", response.Status)
|
||||
|
||||
templates, err := client.List(context.Background(), metav1.ListOptions{})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, templates.Items, 3)
|
||||
|
||||
require.Equal(t, v0alpha1.DefaultTemplateTitle, templates.Items[0].Spec.Title)
|
||||
require.Equal(t, "imported", templates.Items[1].Spec.Title)
|
||||
require.Equal(t, "template", templates.Items[2].Spec.Title)
|
||||
|
||||
t.Run("should be correct kind", func(t *testing.T) {
|
||||
assert.Equal(t,
|
||||
v0alpha1.TemplateGroupSpec{
|
||||
Title: "imported",
|
||||
Content: amConfig.TemplateFiles["imported"],
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindMimir,
|
||||
}, templates.Items[1].Spec)
|
||||
assert.Equal(t,
|
||||
v0alpha1.TemplateGroupSpec{
|
||||
Title: "template",
|
||||
Content: amConfig.TemplateFiles["template"],
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindMimir,
|
||||
}, templates.Items[2].Spec)
|
||||
})
|
||||
|
||||
t.Run("should be provisioned", func(t *testing.T) {
|
||||
for _, tpl := range templates.Items[1:] {
|
||||
assert.EqualValues(t, models.ProvenanceConvertedPrometheus, tpl.GetProvenanceStatus())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should not be able to update", func(t *testing.T) {
|
||||
tpl := templates.Items[1]
|
||||
tpl.Spec.Content = "new content"
|
||||
_, err := client.Update(context.Background(), &tpl, metav1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err)
|
||||
})
|
||||
|
||||
t.Run("should not be able to delete", func(t *testing.T) {
|
||||
err := client.Delete(context.Background(), templates.Items[1].Name, metav1.DeleteOptions{})
|
||||
require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err)
|
||||
})
|
||||
|
||||
t.Run("should not conflict with Grafana kind", func(t *testing.T) {
|
||||
tpl := v0alpha1.TemplateGroup{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: templates.Items[1].Spec,
|
||||
}
|
||||
tpl.Spec.Kind = v0alpha1.TemplateGroupTemplateKindGrafana
|
||||
|
||||
created, err := client.Create(context.Background(), &tpl, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotEqual(t, templates.Items[1].Name, created.Name)
|
||||
})
|
||||
|
||||
t.Run("sort by kind and then name", func(t *testing.T) {
|
||||
templates, err := client.List(context.Background(), metav1.ListOptions{})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, templates.Items, 4)
|
||||
assert.Equal(t, v0alpha1.DefaultTemplateTitle, templates.Items[0].Spec.Title)
|
||||
assert.Equal(t, "imported", templates.Items[1].Spec.Title)
|
||||
assert.Equal(t, v0alpha1.TemplateGroupTemplateKindGrafana, templates.Items[1].Spec.Kind)
|
||||
assert.Equal(t, "imported", templates.Items[2].Spec.Title)
|
||||
assert.Equal(t, v0alpha1.TemplateGroupTemplateKindMimir, templates.Items[2].Spec.Kind)
|
||||
assert.Equal(t, "template", templates.Items[3].Spec.Title)
|
||||
})
|
||||
}
|
||||
@@ -54,6 +54,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) {
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Title: "templateGroup",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindGrafana,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -112,6 +113,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) {
|
||||
require.Equal(t, v0alpha1.TemplateGroupSpec{
|
||||
Title: v0alpha1.DefaultTemplateTitle,
|
||||
Content: defaultDefn.Template,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindGrafana,
|
||||
}, actual.Spec)
|
||||
defaultTemplateGroup = actual
|
||||
})
|
||||
@@ -226,6 +228,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Title: fmt.Sprintf("template-group-1-%s", tc.user.Identity.GetLogin()),
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindGrafana,
|
||||
},
|
||||
}
|
||||
expected.SetProvenanceStatus("")
|
||||
@@ -385,6 +388,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Title: "template-group-1",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindGrafana,
|
||||
},
|
||||
}, v1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -428,6 +432,7 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Title: "template-group-1",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindGrafana,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -510,6 +515,7 @@ func TestIntegrationPatch(t *testing.T) {
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Title: "template-group",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindGrafana,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -568,6 +574,7 @@ func TestIntegrationListSelector(t *testing.T) {
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Title: "test1",
|
||||
Content: `{{ define "test1" }} test {{ end }}`,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindGrafana,
|
||||
},
|
||||
}
|
||||
template1, err := adminClient.Create(ctx, template1, v1.CreateOptions{})
|
||||
@@ -580,6 +587,7 @@ func TestIntegrationListSelector(t *testing.T) {
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Title: "test2",
|
||||
Content: `{{ define "test2" }} test {{ end }}`,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindGrafana,
|
||||
},
|
||||
}
|
||||
template2, err = adminClient.Create(ctx, template2, v1.CreateOptions{})
|
||||
@@ -655,3 +663,37 @@ func TestIntegrationListSelector(t *testing.T) {
|
||||
require.NotEqualf(t, templates.DefaultTemplateName, list.Items[1].Name, "Expected non-default template but got %s", list.Items[1].Name)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntegrationKinds(t *testing.T) {
|
||||
testutil.SkipIntegrationTestInShortMode(t)
|
||||
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
client := common.NewTemplateGroupClient(t, helper.Org1.Admin)
|
||||
|
||||
newTemplate := &v0alpha1.TemplateGroup{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Title: "templateGroup",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
Kind: v0alpha1.TemplateGroupTemplateKindMimir,
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("should not let create Mimir template", func(t *testing.T) {
|
||||
_, err := client.Create(ctx, newTemplate, v1.CreateOptions{})
|
||||
require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err)
|
||||
})
|
||||
|
||||
t.Run("should not let change kind", func(t *testing.T) {
|
||||
newTemplate.Spec.Kind = v0alpha1.TemplateGroupTemplateKindGrafana
|
||||
created, err := client.Create(ctx, newTemplate, v1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
created.Spec.Kind = v0alpha1.TemplateGroupTemplateKindMimir
|
||||
_, err = client.Update(ctx, created, v1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
alertmanager_config: |
|
||||
route:
|
||||
receiver: sinkhole
|
||||
group_by:
|
||||
- alertname
|
||||
receivers:
|
||||
- name: sinkhole
|
||||
template_files:
|
||||
imported: |
|
||||
{{ define "imported" }}
|
||||
{{ end }}
|
||||
template: |
|
||||
{{ define "template" }}
|
||||
{{ template "imported" . }}
|
||||
{{ end }}
|
||||
+12
-1
@@ -3783,18 +3783,29 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"title",
|
||||
"content"
|
||||
"content",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.alerting.notifications.pkg.apis.alertingnotifications.v0alpha1.TemplateGroupTemplateKind"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"com.github.grafana.grafana.apps.alerting.notifications.pkg.apis.alertingnotifications.v0alpha1.TemplateGroupTemplateKind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"grafana",
|
||||
"mimir"
|
||||
]
|
||||
},
|
||||
"com.github.grafana.grafana.apps.alerting.notifications.pkg.apis.alertingnotifications.v0alpha1.TimeInterval": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
||||
@@ -5295,10 +5295,6 @@
|
||||
"com.github.grafana.grafana.apps.provisioning.pkg.apis.provisioning.v0alpha1.MigrateJobOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"history": {
|
||||
"description": "Preserve history (if possible)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"message": {
|
||||
"description": "Message to use when committing the changes in a single commit",
|
||||
"type": "string"
|
||||
@@ -5828,10 +5824,6 @@
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"legacyStorage": {
|
||||
"description": "The backend is using legacy storage FIXME: Not sure where this should be exposed... but we need it somewhere The UI should force the onboarding workflow when this is true",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,7 +10,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
"github.com/grafana/grafana/pkg/util/testutil"
|
||||
@@ -37,6 +39,11 @@ func TestIntegrationOpenAPIs(t *testing.T) {
|
||||
featuremgmt.FlagKubernetesAlertingHistorian,
|
||||
featuremgmt.FlagKubernetesLogsDrilldown,
|
||||
},
|
||||
// Explicitly configure with mode 5 the resources supported by provisioning.
|
||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||
"dashboards.dashboard.grafana.app": {DualWriterMode: rest.Mode5},
|
||||
"folders.folder.grafana.app": {DualWriterMode: rest.Mode5},
|
||||
},
|
||||
})
|
||||
|
||||
t.Run("check valid version response", func(t *testing.T) {
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestIntegrationPluginMeta(t *testing.T) {
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"id": "grafana-piechart-panel", "version": "1.0.0"}
|
||||
"spec": {"id": "piechart", "version": "1.0.0"}
|
||||
}`, plugin1Name))
|
||||
_, err := client.Resource.Create(ctx, plugin1, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -38,7 +38,7 @@ func TestIntegrationPluginMeta(t *testing.T) {
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"id": "grafana-clock-panel", "version": "1.0.0"}
|
||||
"spec": {"id": "table", "version": "1.0.0"}
|
||||
}`, plugin2Name))
|
||||
_, err = client.Resource.Create(ctx, plugin2, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -57,14 +57,14 @@ func TestIntegrationPluginMeta(t *testing.T) {
|
||||
|
||||
foundIDs := make(map[string]bool)
|
||||
for _, item := range response.Result.Items {
|
||||
require.NotNil(t, item.Spec.PluginJSON)
|
||||
foundIDs[item.Spec.PluginJSON.Id] = true
|
||||
require.NotEmpty(t, item.Spec.PluginJSON.Id)
|
||||
require.NotEmpty(t, item.Spec.PluginJSON.Type)
|
||||
require.NotEmpty(t, item.Spec.PluginJSON.Name)
|
||||
require.NotNil(t, item.Spec.PluginJson)
|
||||
foundIDs[item.Spec.PluginJson.Id] = true
|
||||
require.NotEmpty(t, item.Spec.PluginJson.Id)
|
||||
require.NotEmpty(t, item.Spec.PluginJson.Type)
|
||||
require.NotEmpty(t, item.Spec.PluginJson.Name)
|
||||
}
|
||||
require.True(t, foundIDs["grafana-piechart-panel"])
|
||||
require.True(t, foundIDs["grafana-clock-panel"])
|
||||
require.True(t, foundIDs["piechart"])
|
||||
require.True(t, foundIDs["table"])
|
||||
})
|
||||
|
||||
t.Run("list plugin metas with no plugins", func(t *testing.T) {
|
||||
@@ -95,7 +95,7 @@ func TestIntegrationPluginMeta(t *testing.T) {
|
||||
"apiVersion": "plugins.grafana.app/v0alpha1",
|
||||
"kind": "Plugin",
|
||||
"metadata": {"name": "%s"},
|
||||
"spec": {"id": "grafana-piechart-panel", "version": "1.0.0"}
|
||||
"spec": {"id": "piechart", "version": "1.0.0"}
|
||||
}`, pluginName))
|
||||
_, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -109,10 +109,10 @@ func TestIntegrationPluginMeta(t *testing.T) {
|
||||
}, &pluginsv0alpha1.Meta{})
|
||||
|
||||
require.NotNil(t, response.Result)
|
||||
require.NotNil(t, response.Result.Spec.PluginJSON)
|
||||
require.Equal(t, "grafana-piechart-panel", response.Result.Spec.PluginJSON.Id)
|
||||
require.NotEmpty(t, response.Result.Spec.PluginJSON.Name)
|
||||
require.NotEmpty(t, response.Result.Spec.PluginJSON.Type)
|
||||
require.NotNil(t, response.Result.Spec.PluginJson)
|
||||
require.Equal(t, "piechart", response.Result.Spec.PluginJson.Id)
|
||||
require.NotEmpty(t, response.Result.Spec.PluginJson.Name)
|
||||
require.NotEmpty(t, response.Result.Spec.PluginJson.Type)
|
||||
})
|
||||
|
||||
t.Run("get plugin meta for non-existent plugin", func(t *testing.T) {
|
||||
|
||||
@@ -681,12 +681,17 @@ func runGrafana(t *testing.T, options ...grafanaOption) *provisioningTestHelper
|
||||
EnableFeatureToggles: []string{
|
||||
featuremgmt.FlagProvisioning,
|
||||
},
|
||||
// Provisioning requires resources to be fully migrated to unified storage.
|
||||
// Mode5 ensures reads/writes go to unified storage, and EnableMigration
|
||||
// enables the data migration at startup to migrate legacy data.
|
||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||
"dashboards.dashboard.grafana.app": {
|
||||
DualWriterMode: grafanarest.Mode5,
|
||||
DualWriterMode: grafanarest.Mode5,
|
||||
EnableMigration: true,
|
||||
},
|
||||
"folders.folder.grafana.app": {
|
||||
DualWriterMode: grafanarest.Mode5,
|
||||
DualWriterMode: grafanarest.Mode5,
|
||||
EnableMigration: true,
|
||||
},
|
||||
},
|
||||
PermittedProvisioningPaths: ".|" + provisioningPath,
|
||||
|
||||
Reference in New Issue
Block a user