diff --git a/pkg/registry/apis/provisioning/register.go b/pkg/registry/apis/provisioning/register.go index 79559bb2238..e34599c586b 100644 --- a/pkg/registry/apis/provisioning/register.go +++ b/pkg/registry/apis/provisioning/register.go @@ -286,7 +286,6 @@ func (b *APIBuilder) GetAuthorizer() authorizer.Authorizer { Namespace: a.GetNamespace(), Subresource: a.GetSubresource(), }) - if err != nil { return authorizer.DecisionDeny, "failed to perform authorization", err } @@ -622,7 +621,7 @@ func (b *APIBuilder) verifyAgaintsExistingRepositories(cfg *provisioning.Reposit } else { // Folder sync cannot be created if an instance repository exists for _, v := range all { - if v.Spec.Sync.Target == provisioning.SyncTargetTypeInstance { + if v.Spec.Sync.Target == provisioning.SyncTargetTypeInstance && v.Name != cfg.Name { return field.Forbidden(field.NewPath("spec", "sync", "target"), "Cannot create folder repository when instance repository exists: "+v.Name) } diff --git a/pkg/tests/apis/provisioning/helper_test.go b/pkg/tests/apis/provisioning/helper_test.go index 554ad36bff8..48956371779 100644 --- a/pkg/tests/apis/provisioning/helper_test.go +++ b/pkg/tests/apis/provisioning/helper_test.go @@ -468,6 +468,7 @@ type TestRepo struct { Copies map[string]string ExpectedDashboards int ExpectedFolders int + SkipSync bool } func (h *provisioningTestHelper) CreateRepo(t *testing.T, repo TestRepo) { @@ -486,7 +487,7 @@ func (h *provisioningTestHelper) CreateRepo(t *testing.T, repo TestRepo) { templateVars := map[string]any{ "Name": repo.Name, - "SyncEnabled": true, + "SyncEnabled": !repo.SkipSync, "SyncTarget": repo.Target, } if repo.Path != "" { @@ -512,11 +513,13 @@ func (h *provisioningTestHelper) CreateRepo(t *testing.T, repo TestRepo) { } } - // Trigger and wait for initial sync to populate resources - h.SyncAndWait(t, repo.Name, nil) - - // Debug state after initial sync - h.DebugState(t, repo.Name, "AFTER INITIAL SYNC") + if !repo.SkipSync { + // Trigger and wait for initial sync to populate resources + h.SyncAndWait(t, repo.Name, nil) + h.DebugState(t, repo.Name, "AFTER INITIAL SYNC") + } else { + h.DebugState(t, repo.Name, "AFTER REPO CREATION") + } // Verify initial state dashboards, err := h.DashboardsV1.Resource.List(t.Context(), metav1.ListOptions{}) diff --git a/pkg/tests/apis/provisioning/repository_test.go b/pkg/tests/apis/provisioning/repository_test.go index e3213517869..95ebf922dd1 100644 --- a/pkg/tests/apis/provisioning/repository_test.go +++ b/pkg/tests/apis/provisioning/repository_test.go @@ -362,9 +362,6 @@ func TestIntegrationProvisioning_InstanceSyncValidation(t *testing.T) { ctx := context.Background() t.Run("single instance sync is allowed", func(t *testing.T) { - // Ensure clean state - helper.CleanupAllRepos(t) - repoName := "instance-repo-single" testRepo := TestRepo{ Name: repoName, @@ -381,6 +378,33 @@ func TestIntegrationProvisioning_InstanceSyncValidation(t *testing.T) { helper.CleanupAllRepos(t) }) + t.Run("change between folder and instance sync for the same repository if no previous sync happened", func(t *testing.T) { + // Ensure clean state + helper.CleanupAllRepos(t) + + repoName := "instance-repo-change" + testRepo := TestRepo{ + Name: repoName, + Target: "instance", + Copies: map[string]string{}, // No files needed for this test + ExpectedDashboards: 0, + ExpectedFolders: 0, + SkipSync: true, // To avoid initial sync and stats + } + helper.CreateRepo(t, testRepo) + + // Change from instance to folder sync + repo, err := helper.Repositories.Resource.Get(ctx, repoName, metav1.GetOptions{}) + require.NoError(t, err, "failed to get repository") + err = unstructured.SetNestedField(repo.Object, "folder", "spec", "sync", "target") + require.NoError(t, err, "failed to set syncTarget to folder") + _, err = helper.Repositories.Resource.Update(ctx, repo, metav1.UpdateOptions{FieldValidation: "Strict"}) + require.NoError(t, err, "failed to update repository to folder sync") + + // Clean up at end of test + helper.CleanupAllRepos(t) + }) + t.Run("instance sync rejected when any other repository exists", func(t *testing.T) { // Ensure clean state helper.CleanupAllRepos(t)