From 2486dba881ab0e5ae4172a8425dfa81f51ac61aa Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Sat, 4 Oct 2025 17:02:02 +0300 Subject: [PATCH] Provisioning: use kind consistently for provisioning stats (#111977) --- .../pkg/apis/provisioning/v0alpha1/jobs.go | 6 +- .../v0alpha1/zz_generated.openapi.go | 2 +- .../v0alpha1/jobresourcesummary.go | 28 ++--- .../apis/provisioning/jobs/export/folders.go | 10 +- .../provisioning/jobs/export/resources.go | 8 +- .../provisioning/jobs/loki_history_test.go | 24 ++-- .../apis/provisioning/jobs/migrate/clean.go | 15 +-- .../jobs/migrate/legacy_resources.go | 10 +- .../jobs/migrate/legacy_resources_test.go | 2 +- .../apis/provisioning/jobs/progress.go | 20 ++-- .../apis/provisioning/jobs/sync/full.go | 35 +++--- .../apis/provisioning/jobs/sync/full_test.go | 104 +++++++++--------- .../provisioning/jobs/sync/incremental.go | 16 +-- .../jobs/sync/incremental_test.go | 41 +++---- .../apis/provisioning/resources/client.go | 1 + .../provisioning.grafana.app-v0alpha1.json | 6 +- .../provisioning/v0alpha1/endpoints.gen.ts | 2 +- .../features/provisioning/Job/JobSummary.tsx | 4 +- 18 files changed, 169 insertions(+), 165 deletions(-) diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/jobs.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/jobs.go index 847da88fbc5..b96fb1a6d27 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/jobs.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/jobs.go @@ -221,9 +221,9 @@ func (in JobStatus) ToSyncStatus(jobId string) SyncStatus { } type JobResourceSummary struct { - Group string `json:"group,omitempty"` - Resource string `json:"resource,omitempty"` - Total int64 `json:"total,omitempty"` // the count (if known) + Group string `json:"group,omitempty"` + Kind string `json:"kind,omitempty"` + Total int64 `json:"total,omitempty"` // the count (if known) Create int64 `json:"create,omitempty"` Update int64 `json:"update,omitempty"` diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go index 74f7b7d165f..18c385ce59c 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go @@ -846,7 +846,7 @@ func schema_pkg_apis_provisioning_v0alpha1_JobResourceSummary(ref common.Referen Format: "", }, }, - "resource": { + "kind": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", diff --git a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/jobresourcesummary.go b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/jobresourcesummary.go index 75b69663794..ed6a62f651a 100644 --- a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/jobresourcesummary.go +++ b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/jobresourcesummary.go @@ -7,16 +7,16 @@ package v0alpha1 // JobResourceSummaryApplyConfiguration represents a declarative configuration of the JobResourceSummary type for use // with apply. type JobResourceSummaryApplyConfiguration struct { - Group *string `json:"group,omitempty"` - Resource *string `json:"resource,omitempty"` - Total *int64 `json:"total,omitempty"` - Create *int64 `json:"create,omitempty"` - Update *int64 `json:"update,omitempty"` - Delete *int64 `json:"delete,omitempty"` - Write *int64 `json:"write,omitempty"` - Error *int64 `json:"error,omitempty"` - Noop *int64 `json:"noop,omitempty"` - Errors []string `json:"errors,omitempty"` + Group *string `json:"group,omitempty"` + Kind *string `json:"kind,omitempty"` + Total *int64 `json:"total,omitempty"` + Create *int64 `json:"create,omitempty"` + Update *int64 `json:"update,omitempty"` + Delete *int64 `json:"delete,omitempty"` + Write *int64 `json:"write,omitempty"` + Error *int64 `json:"error,omitempty"` + Noop *int64 `json:"noop,omitempty"` + Errors []string `json:"errors,omitempty"` } // JobResourceSummaryApplyConfiguration constructs a declarative configuration of the JobResourceSummary type for use with @@ -33,11 +33,11 @@ func (b *JobResourceSummaryApplyConfiguration) WithGroup(value string) *JobResou return b } -// WithResource sets the Resource field in the declarative configuration to the given value +// WithKind sets the Kind field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Resource field is set to the value of the last call. -func (b *JobResourceSummaryApplyConfiguration) WithResource(value string) *JobResourceSummaryApplyConfiguration { - b.Resource = &value +// If called multiple times, the Kind field is set to the value of the last call. +func (b *JobResourceSummaryApplyConfiguration) WithKind(value string) *JobResourceSummaryApplyConfiguration { + b.Kind = &value return b } diff --git a/pkg/registry/apis/provisioning/jobs/export/folders.go b/pkg/registry/apis/provisioning/jobs/export/folders.go index cb3b4a5f059..4b11f03172a 100644 --- a/pkg/registry/apis/provisioning/jobs/export/folders.go +++ b/pkg/registry/apis/provisioning/jobs/export/folders.go @@ -45,11 +45,11 @@ func ExportFolders(ctx context.Context, repoName string, options provisioning.Ex progress.SetMessage(ctx, "write folders to repository") err := repositoryResources.EnsureFolderTreeExists(ctx, options.Branch, options.Path, tree, func(folder resources.Folder, created bool, err error) error { result := jobs.JobResourceResult{ - Action: repository.FileActionCreated, - Name: folder.ID, - Resource: resources.FolderResource.Resource, - Group: resources.FolderResource.Group, - Path: folder.Path, + Action: repository.FileActionCreated, + Name: folder.ID, + Group: resources.FolderResource.Group, + Kind: resources.FolderKind.Kind, + Path: folder.Path, } if err != nil { diff --git a/pkg/registry/apis/provisioning/jobs/export/resources.go b/pkg/registry/apis/provisioning/jobs/export/resources.go index c07a871815a..445f25faca4 100644 --- a/pkg/registry/apis/provisioning/jobs/export/resources.go +++ b/pkg/registry/apis/provisioning/jobs/export/resources.go @@ -98,10 +98,10 @@ func exportResource(ctx context.Context, return resources.ForEach(ctx, client, func(item *unstructured.Unstructured) (err error) { gvk := item.GroupVersionKind() result := jobs.JobResourceResult{ - Name: item.GetName(), - Resource: resource, - Group: gvk.Group, - Action: repository.FileActionCreated, + Name: item.GetName(), + Group: gvk.Group, + Kind: gvk.Kind, + Action: repository.FileActionCreated, } // Check if resource is already managed by a repository diff --git a/pkg/registry/apis/provisioning/jobs/loki_history_test.go b/pkg/registry/apis/provisioning/jobs/loki_history_test.go index 026e889431d..26d7f01ab4f 100644 --- a/pkg/registry/apis/provisioning/jobs/loki_history_test.go +++ b/pkg/registry/apis/provisioning/jobs/loki_history_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - "github.com/grafana/grafana/apps/provisioning/pkg/loki" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -17,6 +16,7 @@ import ( "k8s.io/apimachinery/pkg/types" provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/apps/provisioning/pkg/loki" ) func TestLokiJobHistory_WriteJob(t *testing.T) { @@ -86,16 +86,16 @@ func TestLokiJobHistory_WriteJob(t *testing.T) { Errors: []string{"warning: deprecated field used"}, Progress: 100.0, Summary: []*provisioning.JobResourceSummary{{ - Group: "dashboard.grafana.app", - Resource: "dashboards", - Total: 10, - Create: 3, - Update: 5, - Delete: 1, - Write: 8, - Error: 1, - Noop: 0, - Errors: []string{"failed to process dashboard-x"}, + Group: "dashboard.grafana.app", + Kind: "Dashboard", + Total: 10, + Create: 3, + Update: 5, + Delete: 1, + Write: 8, + Error: 1, + Noop: 0, + Errors: []string{"failed to process dashboard-x"}, }}, }, } @@ -178,7 +178,7 @@ func TestLokiJobHistory_WriteJob(t *testing.T) { require.Len(t, deserializedJob.Status.Summary, 1) summary := deserializedJob.Status.Summary[0] assert.Equal(t, "dashboard.grafana.app", summary.Group) - assert.Equal(t, "dashboards", summary.Resource) + assert.Equal(t, "Dashboard", summary.Kind) assert.Equal(t, int64(10), summary.Total) assert.Equal(t, int64(3), summary.Create) assert.Equal(t, int64(5), summary.Update) diff --git a/pkg/registry/apis/provisioning/jobs/migrate/clean.go b/pkg/registry/apis/provisioning/jobs/migrate/clean.go index c1c606db71d..c82bbdaea2f 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/clean.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/clean.go @@ -4,12 +4,13 @@ import ( "context" "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "github.com/grafana/grafana/apps/provisioning/pkg/repository" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) //go:generate mockery --name NamespaceCleaner --structname MockNamespaceCleaner --inpackage --filename mock_namespace_cleaner.go --with-expecter @@ -40,10 +41,10 @@ func (c *namespaceCleaner) Clean(ctx context.Context, namespace string, progress if err = resources.ForEach(ctx, client, func(item *unstructured.Unstructured) error { result := jobs.JobResourceResult{ - Name: item.GetName(), - Resource: item.GetKind(), - Group: item.GroupVersionKind().Group, - Action: repository.FileActionDeleted, + Name: item.GetName(), + Kind: item.GetKind(), + Group: item.GroupVersionKind().Group, + Action: repository.FileActionDeleted, } // Skip provisioned resources - only delete unprovisioned (unmanaged) resources @@ -63,7 +64,7 @@ func (c *namespaceCleaner) Clean(ctx context.Context, namespace string, progress } if err := client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}); err != nil { - result.Error = fmt.Errorf("deleting resource %s/%s %s: %w", result.Group, result.Resource, result.Name, err) + result.Error = fmt.Errorf("deleting resource %s/%s %s: %w", result.Group, result.Kind, result.Name, err) progress.Record(ctx, result) return fmt.Errorf("delete resource: %w", err) } diff --git a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go index 5252945cad9..b7b4bb45a4f 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go @@ -204,11 +204,11 @@ func (r *legacyResourceResourceMigrator) Write(ctx context.Context, key *resourc } result := jobs.JobResourceResult{ - Name: parsed.Meta.GetName(), - Resource: r.kind.Resource, - Group: r.kind.Group, - Action: repository.FileActionCreated, - Path: fileName, + Name: parsed.Meta.GetName(), + Group: r.kind.Group, + Kind: parsed.GVK.Kind, + Action: repository.FileActionCreated, + Path: fileName, } if err != nil { diff --git a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go index 3fc6a01e011..89077848f25 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go @@ -667,7 +667,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) { return result.Action == repository.FileActionCreated && result.Name == "test" && result.Error == nil && - result.Resource == "tests" && + result.Kind == "" && // empty kind result.Group == "test.grafana.app" && result.Path == "test/path" })).Return() diff --git a/pkg/registry/apis/provisioning/jobs/progress.go b/pkg/registry/apis/provisioning/jobs/progress.go index 3286ce37a29..f9cea399865 100644 --- a/pkg/registry/apis/provisioning/jobs/progress.go +++ b/pkg/registry/apis/provisioning/jobs/progress.go @@ -35,12 +35,12 @@ func maybeNotifyProgress(threshold time.Duration, fn ProgressFn) ProgressFn { // FIXME: ProgressRecorder should be initialized in the queue type JobResourceResult struct { - Name string - Resource string - Group string - Path string - Action repository.FileAction - Error error + Name string + Group string + Kind string + Path string + Action repository.FileAction + Error error } type jobProgressRecorder struct { @@ -73,7 +73,7 @@ func (r *jobProgressRecorder) Record(ctx context.Context, result JobResourceResu r.mu.Lock() r.resultCount++ - logger := logging.FromContext(ctx).With("path", result.Path, "resource", result.Resource, "group", result.Group, "action", result.Action, "name", result.Name) + logger := logging.FromContext(ctx).With("path", result.Path, "group", result.Group, "kind", result.Kind, "action", result.Action, "name", result.Name) if result.Error != nil { logger.Error("job resource operation failed", "err", result.Error) if len(r.errors) < 20 { @@ -173,12 +173,12 @@ func (r *jobProgressRecorder) summary() []*provisioning.JobResourceSummary { func (r *jobProgressRecorder) updateSummary(result JobResourceResult) { // Note: This method is called from Record() which already holds the lock - key := result.Resource + ":" + result.Group + key := result.Group + ":" + result.Kind summary, exists := r.summaries[key] if !exists { summary = &provisioning.JobResourceSummary{ - Resource: result.Resource, - Group: result.Group, + Group: result.Group, + Kind: result.Kind, } r.summaries[key] = summary } diff --git a/pkg/registry/apis/provisioning/jobs/sync/full.go b/pkg/registry/apis/provisioning/jobs/sync/full.go index 0e0b107171a..075f2fbac5f 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/full.go +++ b/pkg/registry/apis/provisioning/jobs/sync/full.go @@ -4,15 +4,16 @@ import ( "context" "fmt" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/grafana/grafana/apps/provisioning/pkg/repository" "github.com/grafana/grafana/apps/provisioning/pkg/safepath" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" ) func FullSync( @@ -92,9 +93,7 @@ func applyChanges(ctx context.Context, changes []ResourceFileChange, clients res deleteSpan.End() continue } - result.Name = change.Existing.Name - result.Resource = change.Existing.Resource result.Group = change.Existing.Group versionlessGVR := schema.GroupVersionResource{ @@ -103,15 +102,17 @@ func applyChanges(ctx context.Context, changes []ResourceFileChange, clients res } // TODO: should we use the clients or the resource manager instead? - client, _, err := clients.ForResource(deleteCtx, versionlessGVR) + client, gvk, err := clients.ForResource(deleteCtx, versionlessGVR) if err != nil { + result.Kind = versionlessGVR.Resource // could not find a kind result.Error = fmt.Errorf("get client for deleted object: %w", err) progress.Record(deleteCtx, result) continue } + result.Kind = gvk.Kind if err := client.Delete(deleteCtx, change.Existing.Name, metav1.DeleteOptions{}); err != nil { - result.Error = fmt.Errorf("deleting resource %s/%s %s: %w", change.Existing.Group, change.Existing.Resource, change.Existing.Name, err) + result.Error = fmt.Errorf("deleting resource %s/%s %s: %w", change.Existing.Group, gvk.Kind, change.Existing.Name, err) } progress.Record(deleteCtx, result) deleteSpan.End() @@ -122,10 +123,10 @@ func applyChanges(ctx context.Context, changes []ResourceFileChange, clients res if safepath.IsDir(change.Path) { ensureFolderCtx, ensureFolderSpan := tracer.Start(ctx, "provisioning.sync.full.apply_changes.ensure_folder_exists") result := jobs.JobResourceResult{ - Path: change.Path, - Action: change.Action, - Resource: resources.FolderResource.Resource, - Group: resources.FolderResource.Group, + Path: change.Path, + Action: change.Action, + Group: resources.FolderKind.Group, + Kind: resources.FolderKind.Kind, } folder, err := repositoryResources.EnsureFolderPathExist(ensureFolderCtx, change.Path) @@ -147,11 +148,11 @@ func applyChanges(ctx context.Context, changes []ResourceFileChange, clients res writeCtx, writeSpan := tracer.Start(ctx, "provisioning.sync.full.apply_changes.write_resource_from_file") name, gvk, err := repositoryResources.WriteResourceFromFile(writeCtx, change.Path, "") result := jobs.JobResourceResult{ - Path: change.Path, - Action: change.Action, - Name: name, - Resource: gvk.Kind, - Group: gvk.Group, + Path: change.Path, + Action: change.Action, + Name: name, + Group: gvk.Group, + Kind: gvk.Kind, } if err != nil { diff --git a/pkg/registry/apis/provisioning/jobs/sync/full_test.go b/pkg/registry/apis/provisioning/jobs/sync/full_test.go index d5b3b610b80..90e5f4fb0c1 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/full_test.go +++ b/pkg/registry/apis/provisioning/jobs/sync/full_test.go @@ -6,11 +6,6 @@ import ( "fmt" "testing" - provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" - "github.com/grafana/grafana/apps/provisioning/pkg/repository" - "github.com/grafana/grafana/pkg/infra/tracing" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -18,6 +13,12 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" dynamicfake "k8s.io/client-go/dynamic/fake" k8testing "k8s.io/client-go/testing" + + provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/apps/provisioning/pkg/repository" + "github.com/grafana/grafana/pkg/infra/tracing" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" ) func TestFullSync_ContextCancelled(t *testing.T) { @@ -209,11 +210,11 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo Return("test-dashboard", schema.GroupVersionKind{Kind: "Dashboard", Group: "dashboards"}, nil) progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Action: repository.FileActionCreated, - Path: "dashboards/one.json", - Name: "test-dashboard", - Resource: "Dashboard", - Group: "dashboards", + Action: repository.FileActionCreated, + Path: "dashboards/one.json", + Name: "test-dashboard", + Kind: "Dashboard", + Group: "dashboards", }).Return() }, expectedError: "too many errors", @@ -234,11 +235,11 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo Return("test-dashboard", schema.GroupVersionKind{Kind: "Dashboard", Group: "dashboards"}, nil) progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Action: repository.FileActionCreated, - Path: "dashboards/test.json", - Name: "test-dashboard", - Resource: "Dashboard", - Group: "dashboards", + Action: repository.FileActionCreated, + Path: "dashboards/test.json", + Name: "test-dashboard", + Kind: "Dashboard", + Group: "dashboards", }).Return() }, }, @@ -261,7 +262,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo return result.Action == repository.FileActionCreated && result.Path == "dashboards/test.json" && result.Name == "test-dashboard" && - result.Resource == "Dashboard" && + result.Kind == "Dashboard" && result.Group == "dashboards" && result.Error != nil && result.Error.Error() == "writing resource from file dashboards/test.json: write error" @@ -284,11 +285,11 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo Return("test-dashboard", schema.GroupVersionKind{Kind: "Dashboard", Group: "dashboards"}, nil) progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Action: repository.FileActionUpdated, - Path: "dashboards/test.json", - Name: "test-dashboard", - Resource: "Dashboard", - Group: "dashboards", + Action: repository.FileActionUpdated, + Path: "dashboards/test.json", + Name: "test-dashboard", + Kind: "Dashboard", + Group: "dashboards", }).Return() }, }, @@ -311,7 +312,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo return result.Action == repository.FileActionUpdated && result.Path == "dashboards/test.json" && result.Name == "test-dashboard" && - result.Resource == "Dashboard" && + result.Kind == "Dashboard" && result.Group == "dashboards" && result.Error != nil && result.Error.Error() == "writing resource from file dashboards/test.json: write error" @@ -335,9 +336,8 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo Action: repository.FileActionCreated, Path: "one/two/three/", Name: "some-folder", - // FIXME: this is probably inconsistent across the codebase - Resource: "folders", - Group: "folder.grafana.app", + Kind: "Folder", + Group: "folder.grafana.app", }).Return() }, }, @@ -362,7 +362,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo return result.Action == repository.FileActionCreated && result.Path == "one/two/three/" && result.Name == "" && - result.Resource == "folders" && + result.Kind == "Folder" && result.Group == "folder.grafana.app" && result.Error != nil && result.Error.Error() == "ensuring folder exists at path one/two/three/: folder creation error" @@ -378,7 +378,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo Path: "dashboards/test.json", Existing: &provisioning.ResourceListItem{ Name: "test-dashboard", - Resource: "Dashboard", + Resource: "dashboards", Group: "dashboards", }, }, @@ -411,7 +411,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo clients.On("ForResource", mock.Anything, schema.GroupVersionResource{ Group: "dashboards", - Resource: "Dashboard", + Resource: "dashboards", }).Return(fakeDynamicClient.Resource(resources.DashboardResource), schema.GroupVersionKind{ Kind: "Dashboard", Group: "dashboards", @@ -419,12 +419,12 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo }, nil) progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Action: repository.FileActionDeleted, - Path: "dashboards/test.json", - Name: "test-dashboard", - Resource: "Dashboard", - Group: "dashboards", - Error: nil, + Action: repository.FileActionDeleted, + Path: "dashboards/test.json", + Name: "test-dashboard", + Kind: "Dashboard", + Group: "dashboards", + Error: nil, }).Return() }, }, @@ -437,7 +437,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo Path: "dashboards/test.json", Existing: &provisioning.ResourceListItem{ Name: "test-dashboard", - Resource: "Dashboard", + Resource: "dashboards", Group: "dashboards", }, }, @@ -470,7 +470,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo clients.On("ForResource", mock.Anything, schema.GroupVersionResource{ Group: "dashboards", - Resource: "Dashboard", + Resource: "dashboards", }).Return(fakeDynamicClient.Resource(resources.DashboardResource), schema.GroupVersionKind{ Kind: "Dashboard", Group: "dashboards", @@ -481,7 +481,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo return result.Action == repository.FileActionDeleted && result.Path == "dashboards/test.json" && result.Name == "test-dashboard" && - result.Resource == "Dashboard" && + result.Kind == "Dashboard" && result.Group == "dashboards" && result.Error != nil && result.Error.Error() == "deleting resource dashboards/Dashboard test-dashboard: delete failed" @@ -538,7 +538,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo Existing: &provisioning.ResourceListItem{ Name: "test-dashboard", Group: "dashboards", - Resource: "Dashboard", + Resource: "dashboards", }, }, }, @@ -547,16 +547,16 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo clients.On("ForResource", mock.Anything, schema.GroupVersionResource{ Group: "dashboards", - Resource: "Dashboard", + Resource: "dashboards", }).Return(nil, schema.GroupVersionKind{}, errors.New("didn't work")) progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Name: "test-dashboard", - Group: "dashboards", - Resource: "Dashboard", - Action: repository.FileActionDeleted, - Path: "dashboards/test.json", - Error: fmt.Errorf("get client for deleted object: %w", errors.New("didn't work")), + Name: "test-dashboard", + Group: "dashboards", + Kind: "dashboards", // could not find a real kind + Action: repository.FileActionDeleted, + Path: "dashboards/test.json", + Error: fmt.Errorf("get client for deleted object: %w", errors.New("didn't work")), }).Return() }, }, @@ -610,12 +610,12 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo }, nil) progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Action: repository.FileActionDeleted, - Path: "to-be-deleted/", - Name: "test-folder", - Resource: "Folder", - Group: "folders", - Error: nil, + Action: repository.FileActionDeleted, + Path: "to-be-deleted/", + Name: "test-folder", + Kind: "Folder", + Group: "folders", + Error: nil, }).Return() }, }, @@ -672,7 +672,7 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo return result.Action == repository.FileActionDeleted && result.Path == "to-be-deleted/" && result.Name == "test-folder" && - result.Resource == "Folder" && + result.Kind == "Folder" && result.Group == "folders" && result.Error != nil && result.Error.Error() == "deleting resource folders/Folder test-folder: delete failed" diff --git a/pkg/registry/apis/provisioning/jobs/sync/incremental.go b/pkg/registry/apis/provisioning/jobs/sync/incremental.go index f7448bffa16..92639eee103 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/incremental.go +++ b/pkg/registry/apis/provisioning/jobs/sync/incremental.go @@ -63,11 +63,11 @@ func IncrementalSync(ctx context.Context, repo repository.Versioned, previousRef } progress.Record(ensureFolderCtx, jobs.JobResourceResult{ - Path: safeSegment, - Action: repository.FileActionCreated, - Resource: resources.FolderResource.Resource, - Group: resources.FolderResource.Group, - Name: folder, + Path: safeSegment, + Action: repository.FileActionCreated, + Group: resources.FolderResource.Group, + Kind: resources.FolderKind.Kind, + Name: folder, }) ensureFolderSpan.End() continue @@ -95,7 +95,7 @@ func IncrementalSync(ctx context.Context, repo repository.Versioned, previousRef result.Error = fmt.Errorf("writing resource from file %s: %w", change.Path, err) } result.Name = name - result.Resource = gvk.Kind + result.Kind = gvk.Kind result.Group = gvk.Group writeSpan.End() case repository.FileActionDeleted: @@ -106,7 +106,7 @@ func IncrementalSync(ctx context.Context, repo repository.Versioned, previousRef result.Error = fmt.Errorf("removing resource from file %s: %w", change.Path, err) } result.Name = name - result.Resource = gvk.Kind + result.Kind = gvk.Kind result.Group = gvk.Group removeSpan.End() case repository.FileActionRenamed: @@ -117,7 +117,7 @@ func IncrementalSync(ctx context.Context, repo repository.Versioned, previousRef result.Error = fmt.Errorf("renaming resource file from %s to %s: %w", change.PreviousPath, change.Path, err) } result.Name = name - result.Resource = gvk.Kind + result.Kind = gvk.Kind result.Group = gvk.Group renameSpan.End() case repository.FileActionIgnored: diff --git a/pkg/registry/apis/provisioning/jobs/sync/incremental_test.go b/pkg/registry/apis/provisioning/jobs/sync/incremental_test.go index 6562be15f3c..8b98f357695 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/incremental_test.go +++ b/pkg/registry/apis/provisioning/jobs/sync/incremental_test.go @@ -5,13 +5,14 @@ import ( "fmt" "testing" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/grafana/grafana/apps/provisioning/pkg/repository" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/runtime/schema" ) func TestIncrementalSync_ContextCancelled(t *testing.T) { @@ -131,11 +132,11 @@ func TestIncrementalSync(t *testing.T) { // Mock progress recording progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Action: repository.FileActionCreated, - Path: "unsupported/path/", - Resource: resources.FolderResource.Resource, - Group: resources.FolderResource.Group, - Name: "test-folder", + Action: repository.FileActionCreated, + Path: "unsupported/path/", + Kind: resources.FolderKind.Kind, + Group: resources.FolderResource.Group, + Name: "test-folder", }).Return() progress.On("TooManyErrors").Return(nil) @@ -190,11 +191,11 @@ func TestIncrementalSync(t *testing.T) { // Mock progress recording progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Action: repository.FileActionDeleted, - Path: "dashboards/old.json", - Name: "old-dashboard", - Resource: "Dashboard", - Group: "dashboards", + Action: repository.FileActionDeleted, + Path: "dashboards/old.json", + Name: "old-dashboard", + Kind: "Dashboard", + Group: "dashboards", }).Return() progress.On("TooManyErrors").Return(nil) @@ -226,11 +227,11 @@ func TestIncrementalSync(t *testing.T) { // Mock progress recording progress.On("Record", mock.Anything, jobs.JobResourceResult{ - Action: repository.FileActionRenamed, - Path: "dashboards/new.json", - Name: "renamed-dashboard", - Resource: "Dashboard", - Group: "dashboards", + Action: repository.FileActionRenamed, + Path: "dashboards/new.json", + Name: "renamed-dashboard", + Kind: "Dashboard", + Group: "dashboards", }).Return() progress.On("TooManyErrors").Return(nil) @@ -310,7 +311,7 @@ func TestIncrementalSync(t *testing.T) { return result.Action == repository.FileActionCreated && result.Path == "dashboards/test.json" && result.Name == "test-dashboard" && - result.Resource == "Dashboard" && + result.Kind == "Dashboard" && result.Group == "dashboards" && result.Error != nil && result.Error.Error() == "writing resource from file dashboards/test.json: write failed" @@ -346,7 +347,7 @@ func TestIncrementalSync(t *testing.T) { return result.Action == repository.FileActionDeleted && result.Path == "dashboards/old.json" && result.Name == "old-dashboard" && - result.Resource == "Dashboard" && + result.Kind == "Dashboard" && result.Group == "dashboards" && result.Error != nil && result.Error.Error() == "removing resource from file dashboards/old.json: delete failed" diff --git a/pkg/registry/apis/provisioning/resources/client.go b/pkg/registry/apis/provisioning/resources/client.go index 6a68a8add31..f12bcf7b053 100644 --- a/pkg/registry/apis/provisioning/resources/client.go +++ b/pkg/registry/apis/provisioning/resources/client.go @@ -22,6 +22,7 @@ import ( var ( UserResource = iam.UserResourceInfo.GroupVersionResource() FolderResource = folders.FolderResourceInfo.GroupVersionResource() + FolderKind = folders.FolderResourceInfo.GroupVersionKind() DashboardResource = dashboardV1.DashboardResourceInfo.GroupVersionResource() DashboardResourceV2alpha1 = dashboardV2alpha1.DashboardResourceInfo.GroupVersionResource() DashboardResourceV2beta1 = dashboardV2beta1.DashboardResourceInfo.GroupVersionResource() diff --git a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json index 3e2e3a1644b..bdfa6ce9490 100644 --- a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json @@ -3706,14 +3706,14 @@ "group": { "type": "string" }, + "kind": { + "type": "string" + }, "noop": { "description": "No action required (useful for sync)", "type": "integer", "format": "int64" }, - "resource": { - "type": "string" - }, "total": { "type": "integer", "format": "int64" diff --git a/public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts b/public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts index b43299a4d8a..41e4cac3c01 100644 --- a/public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts +++ b/public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts @@ -1010,9 +1010,9 @@ export type JobResourceSummary = { /** Report errors for this resource type This may not be an exhaustive list and recommend looking at the logs for more info */ errors?: string[]; group?: string; + kind?: string; /** No action required (useful for sync) */ noop?: number; - resource?: string; total?: number; update?: number; write?: number; diff --git a/public/app/features/provisioning/Job/JobSummary.tsx b/public/app/features/provisioning/Job/JobSummary.tsx index f91b28a261f..0f9ba17db08 100644 --- a/public/app/features/provisioning/Job/JobSummary.tsx +++ b/public/app/features/provisioning/Job/JobSummary.tsx @@ -11,7 +11,7 @@ const getSummaryColumns = () => [ { id: 'resource', header: 'Resource', - cell: ({ row: { original: item } }: SummaryCell) => item.resource, + cell: ({ row: { original: item } }: SummaryCell) => item.kind, }, { id: 'created', @@ -58,7 +58,7 @@ export function JobSummary({ summary }: Props) { item.resource || ''} + getRowId={(item) => item.kind || ''} pageSize={10} />