Alerting: Support field selectors in time interval API (#90022)

* fix kind of TimeInterval
* register custom fields for selectors
* support field selectors in legacy storage
* support selectors in storage

===== Misc
* refactor conversions to build in one place
* hide implementation of provenance status behind accessors to use the key in selectors
* fix provenance error
This commit is contained in:
Yuri Tseretyan
2024-07-08 15:45:30 -04:00
committed by GitHub
parent 63e715f6a9
commit 5ae5fa3a7a
8 changed files with 221 additions and 43 deletions

View File

@@ -192,15 +192,13 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) {
var expected = &v0alpha1.TimeInterval{
ObjectMeta: v1.ObjectMeta{
Namespace: "default",
Annotations: map[string]string{
"grafana.com/provenance": "",
},
},
Spec: v0alpha1.TimeIntervalSpec{
Name: fmt.Sprintf("time-interval-1-%s", tc.user.Identity.GetLogin()),
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
},
}
expected.SetProvenanceStatus("")
d, err := json.Marshal(expected)
require.NoError(t, err)
@@ -363,7 +361,7 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) {
},
}, v1.CreateOptions{})
require.NoError(t, err)
require.Equal(t, "", created.Annotations["grafana.com/provenance"])
require.Equal(t, "none", created.GetProvenanceStatus())
t.Run("should provide provenance status", func(t *testing.T) {
require.NoError(t, db.SetProvenance(ctx, &definitions.MuteTimeInterval{
@@ -374,7 +372,7 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) {
got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{})
require.NoError(t, err)
require.Equal(t, "API", got.Annotations["grafana.com/provenance"])
require.Equal(t, "API", got.GetProvenanceStatus())
})
t.Run("should not let update if provisioned", func(t *testing.T) {
updated := created.DeepCopy()
@@ -540,3 +538,91 @@ func TestIntegrationTimeIntervalPatch(t *testing.T) {
current = result
})
}
func TestIntegrationTimeIntervalListSelector(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
ctx := context.Background()
helper := getTestHelper(t)
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
require.NoError(t, err)
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
interval1 := &v0alpha1.TimeInterval{
ObjectMeta: v1.ObjectMeta{
Namespace: "default",
},
Spec: v0alpha1.TimeIntervalSpec{
Name: "test1",
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
},
}
interval1, err = adminClient.Create(ctx, interval1, v1.CreateOptions{})
require.NoError(t, err)
interval2 := &v0alpha1.TimeInterval{
ObjectMeta: v1.ObjectMeta{
Namespace: "default",
},
Spec: v0alpha1.TimeIntervalSpec{
Name: "test2",
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
},
}
interval2, err = adminClient.Create(ctx, interval2, v1.CreateOptions{})
require.NoError(t, err)
env := helper.GetEnv()
ac := acimpl.ProvideAccessControl(env.FeatureToggles, zanzana.NewNoopClient())
db, err := store.ProvideDBStore(env.Cfg, env.FeatureToggles, env.SQLStore, &foldertest.FakeService{}, &dashboards.FakeDashboardService{}, ac)
require.NoError(t, err)
require.NoError(t, db.SetProvenance(ctx, &definitions.MuteTimeInterval{
MuteTimeInterval: config.MuteTimeInterval{
Name: interval2.Spec.Name,
},
}, helper.Org1.Admin.Identity.GetOrgID(), "API"))
interval2, err = adminClient.Get(ctx, interval2.Name, v1.GetOptions{})
require.NoError(t, err)
intervals, err := adminClient.List(ctx, v1.ListOptions{})
require.NoError(t, err)
require.Len(t, intervals.Items, 2)
t.Run("should filter by interval name", func(t *testing.T) {
list, err := adminClient.List(ctx, v1.ListOptions{
FieldSelector: "spec.name=" + interval1.Spec.Name,
})
require.NoError(t, err)
require.Len(t, list.Items, 1)
require.Equal(t, interval1.Name, list.Items[0].Name)
})
t.Run("should filter by interval metadata name", func(t *testing.T) {
list, err := adminClient.List(ctx, v1.ListOptions{
FieldSelector: "metadata.name=" + interval2.Name,
})
require.NoError(t, err)
require.Len(t, list.Items, 1)
require.Equal(t, interval2.Name, list.Items[0].Name)
})
t.Run("should filter by multiple filters", func(t *testing.T) {
list, err := adminClient.List(ctx, v1.ListOptions{
FieldSelector: fmt.Sprintf("metadata.name=%s,metadata.provenance=%s", interval2.Name, "API"),
})
require.NoError(t, err)
require.Len(t, list.Items, 1)
require.Equal(t, interval2.Name, list.Items[0].Name)
})
t.Run("should be empty when filter does not match", func(t *testing.T) {
list, err := adminClient.List(ctx, v1.ListOptions{
FieldSelector: fmt.Sprintf("metadata.name=%s,metadata.provenance=%s", interval2.Name, "unknown"),
})
require.NoError(t, err)
require.Empty(t, list.Items)
})
}