Provisioning: Fix patching released resources when Repository is deleted (#110295)

* Provisioning: Use merge patch instead of json path to release orphan resources

* rolling back to json Patch

* adding TODO for testing

* adding integration test

* using struct

* addressing comments on tests
This commit is contained in:
Daniele Stefano Ferru
2025-09-02 21:13:43 +02:00
committed by GitHub
parent d97836f407
commit 451d6abe15
2 changed files with 122 additions and 6 deletions
@@ -15,6 +15,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/utils"
@@ -682,3 +683,78 @@ func TestIntegrationProvisioning_ImportAllPanelsFromLocalRepository(t *testing.T
require.Error(t, err, "should delete the internal resource")
require.True(t, apierrors.IsNotFound(err))
}
func TestIntegrationProvisioning_DeleteRepositoryAndReleaseResources(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
helper := runGrafana(t)
ctx := context.Background()
const repo = "gh-repo"
testRepo := TestRepo{
Name: repo,
Template: "testdata/github-readonly.json.tmpl",
Target: "folder",
ExpectedDashboards: 3,
ExpectedFolders: 3,
}
helper.CreateRepo(t, testRepo)
// Checking resources are there and are managed
foundFolders, err := helper.Folders.Resource.List(ctx, metav1.ListOptions{})
require.NoError(t, err, "can list folders")
for _, v := range foundFolders.Items {
assert.Contains(t, v.GetAnnotations(), utils.AnnoKeyManagerKind)
assert.Contains(t, v.GetAnnotations(), utils.AnnoKeyManagerIdentity)
}
foundDashboards, err := helper.DashboardsV1.Resource.List(ctx, metav1.ListOptions{})
require.NoError(t, err, "can list dashboards")
for _, v := range foundDashboards.Items {
assert.Contains(t, v.GetAnnotations(), utils.AnnoKeyManagerKind)
assert.Contains(t, v.GetAnnotations(), utils.AnnoKeyManagerIdentity)
assert.Contains(t, v.GetAnnotations(), utils.AnnoKeySourcePath)
assert.Contains(t, v.GetAnnotations(), utils.AnnoKeySourceChecksum)
}
_, err = helper.Repositories.Resource.Patch(ctx, repo, types.JSONPatchType, []byte(`[
{
"op": "replace",
"path": "/metadata/finalizers",
"value": ["cleanup", "release-orphan-resources"]
}
]`), metav1.PatchOptions{})
require.NoError(t, err, "should successfully patch finalizers")
err = helper.Repositories.Resource.Delete(ctx, repo, metav1.DeleteOptions{})
require.NoError(t, err, "should delete repository")
require.EventuallyWithT(t, func(collect *assert.CollectT) {
_, err := helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{})
assert.True(collect, apierrors.IsNotFound(err), "repository should be deleted")
}, time.Second*10, time.Millisecond*50, "repository should be deleted")
require.EventuallyWithT(t, func(collect *assert.CollectT) {
foundDashboards, err := helper.DashboardsV1.Resource.List(ctx, metav1.ListOptions{})
assert.NoError(t, err, "can list values")
for _, v := range foundDashboards.Items {
assert.NotContains(t, v.GetAnnotations(), utils.AnnoKeyManagerKind)
assert.NotContains(t, v.GetAnnotations(), utils.AnnoKeyManagerIdentity)
assert.NotContains(t, v.GetAnnotations(), utils.AnnoKeySourcePath)
assert.NotContains(t, v.GetAnnotations(), utils.AnnoKeySourceChecksum)
}
}, time.Second*20, time.Millisecond*10, "Expected dashboards to be released")
require.EventuallyWithT(t, func(collect *assert.CollectT) {
foundFolders, err := helper.Folders.Resource.List(ctx, metav1.ListOptions{})
assert.NoError(t, err, "can list values")
for _, v := range foundFolders.Items {
assert.NotContains(t, v.GetAnnotations(), utils.AnnoKeyManagerKind)
assert.NotContains(t, v.GetAnnotations(), utils.AnnoKeyManagerIdentity)
assert.NotContains(t, v.GetAnnotations(), utils.AnnoKeySourcePath)
assert.NotContains(t, v.GetAnnotations(), utils.AnnoKeySourceChecksum)
}
}, time.Second*20, time.Millisecond*10, "Expected folders to be released")
}