From eb3507f01a1a22a903494465f393444a5c985fba Mon Sep 17 00:00:00 2001 From: Andrew Costa Date: Wed, 28 Jun 2023 16:10:46 -0700 Subject: [PATCH 1/3] Org repository sets deletion time [#2605] Co-authored-by: Dave Walter --- api/repositories/org_repository.go | 6 ++++++ api/repositories/org_repository_test.go | 1 + 2 files changed, 7 insertions(+) diff --git a/api/repositories/org_repository.go b/api/repositories/org_repository.go index 6423f70bc..d9070f250 100644 --- a/api/repositories/org_repository.go +++ b/api/repositories/org_repository.go @@ -244,6 +244,11 @@ func (r *OrgRepo) PatchOrgMetadata(ctx context.Context, authInfo authorization.I func cfOrgToOrgRecord(cfOrg korifiv1alpha1.CFOrg) OrgRecord { updatedAtTime, _ := getTimeLastUpdatedTimestamp(&cfOrg.ObjectMeta) + deletedAtTime := "" + if cfOrg.DeletionTimestamp != nil { + deletedAtTime = formatTimestamp(*cfOrg.DeletionTimestamp) + } + return OrgRecord{ GUID: cfOrg.Name, Name: cfOrg.Spec.DisplayName, @@ -252,5 +257,6 @@ func cfOrgToOrgRecord(cfOrg korifiv1alpha1.CFOrg) OrgRecord { Annotations: cfOrg.Annotations, CreatedAt: formatTimestamp(cfOrg.CreationTimestamp), UpdatedAt: updatedAtTime, + DeletedAt: deletedAtTime, } } diff --git a/api/repositories/org_repository_test.go b/api/repositories/org_repository_test.go index 8299c691a..716e49aae 100644 --- a/api/repositories/org_repository_test.go +++ b/api/repositories/org_repository_test.go @@ -140,6 +140,7 @@ var _ = Describe("OrgRepository", func() { updatedAt, err := time.Parse(time.RFC3339, org.UpdatedAt) Expect(err).NotTo(HaveOccurred()) Expect(updatedAt).To(BeTemporally("~", time.Now(), 2*time.Second)) + Expect(org.DeletedAt).To(BeEmpty()) Expect(org.Labels).To(Equal(map[string]string{"test-label-key": "test-label-val"})) Expect(org.Annotations).To(Equal(map[string]string{"test-annotation-key": "test-annotation-val"})) }) From 214e34d60879b0de3d4111453a4e14ff34fb0f01 Mon Sep 17 00:00:00 2001 From: Andrew Costa Date: Wed, 28 Jun 2023 17:26:58 -0700 Subject: [PATCH 2/3] Implement space deletion job - Refactor org deletion helper to handle all types. [#2604] Co-authored-by: Dave Walter --- api/handlers/job.go | 67 ++++++++++------ api/handlers/job_test.go | 109 ++++++++++++++++++++++++++- api/main.go | 1 + api/repositories/space_repository.go | 7 ++ 4 files changed, 159 insertions(+), 25 deletions(-) diff --git a/api/handlers/job.go b/api/handlers/job.go index 885e5f8c5..248506936 100644 --- a/api/handlers/job.go +++ b/api/handlers/job.go @@ -11,6 +11,7 @@ import ( "code.cloudfoundry.org/korifi/api/authorization" apierrors "code.cloudfoundry.org/korifi/api/errors" "code.cloudfoundry.org/korifi/api/presenter" + "code.cloudfoundry.org/korifi/api/repositories" "code.cloudfoundry.org/korifi/api/routing" "github.com/go-logr/logr" @@ -34,12 +35,14 @@ const JobResourceType = "Job" type Job struct { serverURL url.URL orgRepo CFOrgRepository + spaceRepo CFSpaceRepository } -func NewJob(serverURL url.URL, orgRepo CFOrgRepository) *Job { +func NewJob(serverURL url.URL, orgRepo CFOrgRepository, spaceRepo CFSpaceRepository) *Job { return &Job{ serverURL: serverURL, orgRepo: orgRepo, + spaceRepo: spaceRepo, } } @@ -66,10 +69,10 @@ func (h *Job) get(r *http.Request) (*routing.Response, error) { switch jobType { case syncSpacePrefix: jobResponse = presenter.ForManifestApplyJob(jobGUID, resourceGUID, h.serverURL) - case appDeletePrefix, spaceDeletePrefix, routeDeletePrefix, domainDeletePrefix, roleDeletePrefix: + case appDeletePrefix, routeDeletePrefix, domainDeletePrefix, roleDeletePrefix: jobResponse = presenter.ForJob(jobGUID, []presenter.JobResponseError{}, presenter.StateComplete, jobType, h.serverURL) - case orgDeletePrefix: - jobResponse, err = h.handleOrgDelete(r.Context(), resourceGUID, jobGUID) + case orgDeletePrefix, spaceDeletePrefix: + jobResponse, err = h.handleDeleteJob(r.Context(), resourceGUID, jobGUID, jobType) if err != nil { return nil, err } @@ -84,11 +87,32 @@ func (h *Job) get(r *http.Request) (*routing.Response, error) { return routing.NewResponse(http.StatusOK).WithBody(jobResponse), nil } -func (h *Job) handleOrgDelete(ctx context.Context, resourceGUID, jobGUID string) (presenter.JobResponse, error) { +func (h *Job) handleDeleteJob(ctx context.Context, resourceGUID, jobGUID, jobType string) (presenter.JobResponse, error) { authInfo, _ := authorization.InfoFromContext(ctx) - log := logr.FromContextOrDiscard(ctx).WithName("handlers.job.get.handleOrgDelete") + log := logr.FromContextOrDiscard(ctx).WithName("handlers.job.get.handleDeleteJob") + + var ( + org repositories.OrgRecord + space repositories.SpaceRecord + err error + resourceName string + resourceType string + deletedAt string + ) + + switch jobType { + case orgDeletePrefix: + org, err = h.orgRepo.GetOrg(ctx, authInfo, resourceGUID) + resourceName = org.Name + resourceType = "Org" + deletedAt = org.DeletedAt + case spaceDeletePrefix: + space, err = h.spaceRepo.GetSpace(ctx, authInfo, resourceGUID) + resourceName = space.Name + resourceType = "Space" + deletedAt = space.DeletedAt + } - org, err := h.orgRepo.GetOrg(ctx, authInfo, resourceGUID) if err != nil { switch err.(type) { case apierrors.NotFoundError, apierrors.ForbiddenError: @@ -96,37 +120,36 @@ func (h *Job) handleOrgDelete(ctx context.Context, resourceGUID, jobGUID string) jobGUID, []presenter.JobResponseError{}, presenter.StateComplete, - orgDeletePrefix, + jobType, h.serverURL, ), nil default: return presenter.JobResponse{}, apierrors.LogAndReturn( log, - apierrors.ForbiddenAsNotFound(err), - "failed to fetch org from Kubernetes", - "OrgGUID", resourceGUID, + err, + "failed to fetch "+resourceType+" from Kubernetes", + resourceType+"GUID", resourceGUID, ) } } - // This logic can be refactored into a generic helper for all resource types. - if org.DeletedAt == "" { + if deletedAt == "" { return presenter.JobResponse{}, apierrors.LogAndReturn( log, apierrors.NewNotFoundError(fmt.Errorf("job %q not found", jobGUID), JobResourceType), - "org not marked for deletion", - "OrgGUID", resourceGUID, + resourceType+" not marked for deletion", + resourceType+"GUID", resourceGUID, ) } - deletionTime, err := time.Parse(time.RFC3339Nano, org.DeletedAt) + deletionTime, err := time.Parse(time.RFC3339Nano, deletedAt) if err != nil { return presenter.JobResponse{}, apierrors.LogAndReturn( log, err, - "failed to parse org deletion time", - "name", org.Name, - "timestamp", org.DeletedAt, + "failed to parse "+resourceType+" deletion time", + "name", resourceName, + "timestamp", deletedAt, ) } @@ -135,7 +158,7 @@ func (h *Job) handleOrgDelete(ctx context.Context, resourceGUID, jobGUID string) jobGUID, []presenter.JobResponseError{}, presenter.StateProcessing, - orgDeletePrefix, + jobType, h.serverURL, ), nil } else { @@ -143,11 +166,11 @@ func (h *Job) handleOrgDelete(ctx context.Context, resourceGUID, jobGUID string) jobGUID, []presenter.JobResponseError{{ Code: 10008, - Detail: fmt.Sprintf("CFOrg deletion timed out. Check for lingering resources in the %q namespace", org.GUID), + Detail: fmt.Sprintf("%s deletion timed out. Check for remaining resources in the %q namespace", resourceType, resourceGUID), Title: "CF-UnprocessableEntity", }}, presenter.StateFailed, - orgDeletePrefix, + jobType, h.serverURL, ), nil } diff --git a/api/handlers/job_test.go b/api/handlers/job_test.go index 0e6dc66ea..9dbff7cdf 100644 --- a/api/handlers/job_test.go +++ b/api/handlers/job_test.go @@ -24,13 +24,15 @@ var _ = Describe("Job", func() { jobGUID string req *http.Request orgRepo *fake.OrgRepository + spaceRepo *fake.SpaceRepository ) BeforeEach(func() { spaceGUID = uuid.NewString() orgRepo = new(fake.OrgRepository) - apiHandler := handlers.NewJob(*serverURL, orgRepo) + spaceRepo = new(fake.SpaceRepository) + apiHandler := handlers.NewJob(*serverURL, orgRepo, spaceRepo) routerBuilder.LoadRoutes(apiHandler) }) @@ -73,7 +75,6 @@ var _ = Describe("Job", func() { ))) }, Entry("app delete", "app.delete", "cf-app-guid"), - Entry("space delete", "space.delete", "cf-space-guid"), Entry("route delete", "route.delete", "cf-route-guid"), Entry("domain delete", "domain.delete", "cf-domain-guid"), Entry("role delete", "role.delete", "cf-role-guid"), @@ -150,7 +151,7 @@ var _ = Describe("Job", func() { MatchJSONPath("$.state", "FAILED"), MatchJSONPath("$.errors", ConsistOf(map[string]interface{}{ "code": float64(10008), - "detail": fmt.Sprintf("CFOrg deletion timed out. Check for lingering resources in the %q namespace", resourceGUID), + "detail": fmt.Sprintf("Org deletion timed out. Check for remaining resources in the %q namespace", resourceGUID), "title": "CF-UnprocessableEntity", })), ))) @@ -190,5 +191,107 @@ var _ = Describe("Job", func() { }) }) }) + + Describe("space delete", func() { + const ( + operation = "space.delete" + resourceGUID = "cf-space-guid" + ) + + BeforeEach(func() { + jobGUID = operation + "~" + resourceGUID + }) + + When("the space deletion is in progress", func() { + BeforeEach(func() { + spaceRepo.GetSpaceReturns(repositories.SpaceRecord{ + GUID: "cf-space-guid", + DeletedAt: time.Now().Format(time.RFC3339Nano), + }, nil) + }) + + It("returns a processing status", func() { + Expect(rr).To(HaveHTTPBody(SatisfyAll( + MatchJSONPath("$.guid", jobGUID), + MatchJSONPath("$.links.self.href", defaultServerURL+"/v3/jobs/"+jobGUID), + MatchJSONPath("$.operation", operation), + MatchJSONPath("$.state", "PROCESSING"), + MatchJSONPath("$.errors", BeEmpty()), + ))) + }) + }) + + When("the space does not exist", func() { + BeforeEach(func() { + spaceRepo.GetSpaceReturns(repositories.SpaceRecord{}, apierrors.NewNotFoundError(nil, repositories.SpaceResourceType)) + }) + + It("returns a complete status", func() { + Expect(rr).To(HaveHTTPBody(SatisfyAll( + MatchJSONPath("$.guid", jobGUID), + MatchJSONPath("$.links.self.href", defaultServerURL+"/v3/jobs/"+jobGUID), + MatchJSONPath("$.operation", operation), + MatchJSONPath("$.state", "COMPLETE"), + MatchJSONPath("$.errors", BeEmpty()), + ))) + }) + }) + + When("the space deletion times out", func() { + BeforeEach(func() { + spaceRepo.GetSpaceReturns(repositories.SpaceRecord{ + GUID: "cf-space-guid", + DeletedAt: (time.Now().Add(-180 * time.Second)).Format(time.RFC3339Nano), + }, nil) + }) + + It("returns a failed status", func() { + Expect(rr).To(HaveHTTPBody(SatisfyAll( + MatchJSONPath("$.guid", jobGUID), + MatchJSONPath("$.links.self.href", defaultServerURL+"/v3/jobs/"+jobGUID), + MatchJSONPath("$.operation", operation), + MatchJSONPath("$.state", "FAILED"), + MatchJSONPath("$.errors", ConsistOf(map[string]interface{}{ + "code": float64(10008), + "detail": fmt.Sprintf("Space deletion timed out. Check for remaining resources in the %q namespace", resourceGUID), + "title": "CF-UnprocessableEntity", + })), + ))) + }) + }) + + When("the user does not have permission to see the space", func() { + BeforeEach(func() { + spaceRepo.GetSpaceReturns(repositories.SpaceRecord{}, apierrors.NewForbiddenError(nil, repositories.SpaceResourceType)) + }) + + It("returns a complete status", func() { + Expect(rr).To(HaveHTTPBody(SatisfyAll( + MatchJSONPath("$.guid", jobGUID), + MatchJSONPath("$.links.self.href", defaultServerURL+"/v3/jobs/"+jobGUID), + MatchJSONPath("$.operation", operation), + MatchJSONPath("$.state", "COMPLETE"), + MatchJSONPath("$.errors", BeEmpty()), + ))) + }) + }) + + When("the space has not been marked for deletion", func() { + BeforeEach(func() { + spaceRepo.GetSpaceReturns(repositories.SpaceRecord{ + GUID: resourceGUID, + }, nil) + }) + + It("returns a not found error", func() { + Expect(rr).To(HaveHTTPStatus(http.StatusNotFound)) + Expect(rr).To(HaveHTTPBody(SatisfyAll( + MatchJSONPath("$.errors[0].code", float64(10010)), + MatchJSONPath("$.errors[0].detail", "Job not found. Ensure it exists and you have access to it."), + MatchJSONPath("$.errors[0].title", "CF-ResourceNotFound"), + ))) + }) + }) + }) }) }) diff --git a/api/main.go b/api/main.go index 8ef783b45..344e6ec57 100644 --- a/api/main.go +++ b/api/main.go @@ -328,6 +328,7 @@ func main() { handlers.NewJob( *serverURL, orgRepo, + spaceRepo, ), handlers.NewLogCache( appRepo, diff --git a/api/repositories/space_repository.go b/api/repositories/space_repository.go index e6e7abdd7..5130413e1 100644 --- a/api/repositories/space_repository.go +++ b/api/repositories/space_repository.go @@ -53,6 +53,7 @@ type SpaceRecord struct { Annotations map[string]string CreatedAt string UpdatedAt string + DeletedAt string } type SpaceRepo struct { @@ -236,6 +237,11 @@ func (r *SpaceRepo) GetSpace(ctx context.Context, info authorization.Info, space func cfSpaceToSpaceRecord(cfSpace korifiv1alpha1.CFSpace) SpaceRecord { updatedAtTime, _ := getTimeLastUpdatedTimestamp(&cfSpace.ObjectMeta) + deletedAtTime := "" + if cfSpace.DeletionTimestamp != nil { + deletedAtTime = formatTimestamp(*cfSpace.DeletionTimestamp) + } + return SpaceRecord{ Name: cfSpace.Spec.DisplayName, GUID: cfSpace.Name, @@ -244,6 +250,7 @@ func cfSpaceToSpaceRecord(cfSpace korifiv1alpha1.CFSpace) SpaceRecord { Labels: cfSpace.Labels, CreatedAt: formatTimestamp(cfSpace.CreationTimestamp), UpdatedAt: updatedAtTime, + DeletedAt: deletedAtTime, } } From 9677715d65730870e22c84f9a5dc8426150e89c2 Mon Sep 17 00:00:00 2001 From: Ashwin Krishna Date: Thu, 29 Jun 2023 18:41:25 -0700 Subject: [PATCH 3/3] Fix Org/space delete job issues - Add a retry loop to wait for the deletion timestamp to propagate. - Added a GetOrgUnfiltered function to the org repository to avoid falsely returning a not found error when the role binding is deleted from an org during deletion. - Consolidate CFSpaceRepository and SpaceRepository interfaces. [#2604] [#2605] Co-authored-by: Dave Walter Co-authored-by: Julian Hjortshoj --- api/authorization/user_client_factory_test.go | 1 + api/handlers/app.go | 4 +- api/handlers/app_test.go | 4 +- ...{org_repository.go => cforg_repository.go} | 151 ++++-- api/handlers/fake/cfspace_repository.go | 83 ++++ api/handlers/fake/space_repository.go | 450 ------------------ api/handlers/job.go | 105 ++-- api/handlers/job_test.go | 18 +- api/handlers/org.go | 3 +- api/handlers/org_test.go | 4 +- api/handlers/route.go | 4 +- api/handlers/route_test.go | 4 +- api/handlers/service_instance.go | 4 +- api/handlers/service_instance_test.go | 4 +- api/handlers/space.go | 12 +- api/handlers/space_manifest.go | 14 +- api/handlers/space_test.go | 4 +- api/repositories/org_repository.go | 15 + api/repositories/org_repository_test.go | 44 ++ api/repositories/space_repository_test.go | 24 +- 20 files changed, 372 insertions(+), 580 deletions(-) rename api/handlers/fake/{org_repository.go => cforg_repository.go} (62%) delete mode 100644 api/handlers/fake/space_repository.go diff --git a/api/authorization/user_client_factory_test.go b/api/authorization/user_client_factory_test.go index f1c57ee4c..036bf58b5 100644 --- a/api/authorization/user_client_factory_test.go +++ b/api/authorization/user_client_factory_test.go @@ -10,6 +10,7 @@ import ( apierrors "code.cloudfoundry.org/korifi/api/errors" "code.cloudfoundry.org/korifi/tests/helpers" "code.cloudfoundry.org/korifi/tests/matchers" + "github.com/google/uuid" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" diff --git a/api/handlers/app.go b/api/handlers/app.go index 6e6cd840a..924363f86 100644 --- a/api/handlers/app.go +++ b/api/handlers/app.go @@ -61,7 +61,7 @@ type App struct { processRepo CFProcessRepository routeRepo CFRouteRepository domainRepo CFDomainRepository - spaceRepo SpaceRepository + spaceRepo CFSpaceRepository packageRepo CFPackageRepository requestValidator RequestValidator } @@ -73,7 +73,7 @@ func NewApp( processRepo CFProcessRepository, routeRepo CFRouteRepository, domainRepo CFDomainRepository, - spaceRepo SpaceRepository, + spaceRepo CFSpaceRepository, packageRepo CFPackageRepository, requestValidator RequestValidator, ) *App { diff --git a/api/handlers/app_test.go b/api/handlers/app_test.go index c98875756..bce7c2c6b 100644 --- a/api/handlers/app_test.go +++ b/api/handlers/app_test.go @@ -34,7 +34,7 @@ var _ = Describe("App", func() { processRepo *fake.CFProcessRepository routeRepo *fake.CFRouteRepository domainRepo *fake.CFDomainRepository - spaceRepo *fake.SpaceRepository + spaceRepo *fake.CFSpaceRepository packageRepo *fake.CFPackageRepository requestValidator *fake.RequestValidator req *http.Request @@ -48,7 +48,7 @@ var _ = Describe("App", func() { processRepo = new(fake.CFProcessRepository) routeRepo = new(fake.CFRouteRepository) domainRepo = new(fake.CFDomainRepository) - spaceRepo = new(fake.SpaceRepository) + spaceRepo = new(fake.CFSpaceRepository) packageRepo = new(fake.CFPackageRepository) requestValidator = new(fake.RequestValidator) diff --git a/api/handlers/fake/org_repository.go b/api/handlers/fake/cforg_repository.go similarity index 62% rename from api/handlers/fake/org_repository.go rename to api/handlers/fake/cforg_repository.go index b251ec3f9..78ec5da35 100644 --- a/api/handlers/fake/org_repository.go +++ b/api/handlers/fake/cforg_repository.go @@ -10,7 +10,7 @@ import ( "code.cloudfoundry.org/korifi/api/repositories" ) -type OrgRepository struct { +type CFOrgRepository struct { CreateOrgStub func(context.Context, authorization.Info, repositories.CreateOrgMessage) (repositories.OrgRecord, error) createOrgMutex sync.RWMutex createOrgArgsForCall []struct { @@ -54,6 +54,21 @@ type OrgRepository struct { result1 repositories.OrgRecord result2 error } + GetOrgUnfilteredStub func(context.Context, authorization.Info, string) (repositories.OrgRecord, error) + getOrgUnfilteredMutex sync.RWMutex + getOrgUnfilteredArgsForCall []struct { + arg1 context.Context + arg2 authorization.Info + arg3 string + } + getOrgUnfilteredReturns struct { + result1 repositories.OrgRecord + result2 error + } + getOrgUnfilteredReturnsOnCall map[int]struct { + result1 repositories.OrgRecord + result2 error + } ListOrgsStub func(context.Context, authorization.Info, repositories.ListOrgsMessage) ([]repositories.OrgRecord, error) listOrgsMutex sync.RWMutex listOrgsArgsForCall []struct { @@ -88,7 +103,7 @@ type OrgRepository struct { invocationsMutex sync.RWMutex } -func (fake *OrgRepository) CreateOrg(arg1 context.Context, arg2 authorization.Info, arg3 repositories.CreateOrgMessage) (repositories.OrgRecord, error) { +func (fake *CFOrgRepository) CreateOrg(arg1 context.Context, arg2 authorization.Info, arg3 repositories.CreateOrgMessage) (repositories.OrgRecord, error) { fake.createOrgMutex.Lock() ret, specificReturn := fake.createOrgReturnsOnCall[len(fake.createOrgArgsForCall)] fake.createOrgArgsForCall = append(fake.createOrgArgsForCall, struct { @@ -109,26 +124,26 @@ func (fake *OrgRepository) CreateOrg(arg1 context.Context, arg2 authorization.In return fakeReturns.result1, fakeReturns.result2 } -func (fake *OrgRepository) CreateOrgCallCount() int { +func (fake *CFOrgRepository) CreateOrgCallCount() int { fake.createOrgMutex.RLock() defer fake.createOrgMutex.RUnlock() return len(fake.createOrgArgsForCall) } -func (fake *OrgRepository) CreateOrgCalls(stub func(context.Context, authorization.Info, repositories.CreateOrgMessage) (repositories.OrgRecord, error)) { +func (fake *CFOrgRepository) CreateOrgCalls(stub func(context.Context, authorization.Info, repositories.CreateOrgMessage) (repositories.OrgRecord, error)) { fake.createOrgMutex.Lock() defer fake.createOrgMutex.Unlock() fake.CreateOrgStub = stub } -func (fake *OrgRepository) CreateOrgArgsForCall(i int) (context.Context, authorization.Info, repositories.CreateOrgMessage) { +func (fake *CFOrgRepository) CreateOrgArgsForCall(i int) (context.Context, authorization.Info, repositories.CreateOrgMessage) { fake.createOrgMutex.RLock() defer fake.createOrgMutex.RUnlock() argsForCall := fake.createOrgArgsForCall[i] return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *OrgRepository) CreateOrgReturns(result1 repositories.OrgRecord, result2 error) { +func (fake *CFOrgRepository) CreateOrgReturns(result1 repositories.OrgRecord, result2 error) { fake.createOrgMutex.Lock() defer fake.createOrgMutex.Unlock() fake.CreateOrgStub = nil @@ -138,7 +153,7 @@ func (fake *OrgRepository) CreateOrgReturns(result1 repositories.OrgRecord, resu }{result1, result2} } -func (fake *OrgRepository) CreateOrgReturnsOnCall(i int, result1 repositories.OrgRecord, result2 error) { +func (fake *CFOrgRepository) CreateOrgReturnsOnCall(i int, result1 repositories.OrgRecord, result2 error) { fake.createOrgMutex.Lock() defer fake.createOrgMutex.Unlock() fake.CreateOrgStub = nil @@ -154,7 +169,7 @@ func (fake *OrgRepository) CreateOrgReturnsOnCall(i int, result1 repositories.Or }{result1, result2} } -func (fake *OrgRepository) DeleteOrg(arg1 context.Context, arg2 authorization.Info, arg3 repositories.DeleteOrgMessage) error { +func (fake *CFOrgRepository) DeleteOrg(arg1 context.Context, arg2 authorization.Info, arg3 repositories.DeleteOrgMessage) error { fake.deleteOrgMutex.Lock() ret, specificReturn := fake.deleteOrgReturnsOnCall[len(fake.deleteOrgArgsForCall)] fake.deleteOrgArgsForCall = append(fake.deleteOrgArgsForCall, struct { @@ -175,26 +190,26 @@ func (fake *OrgRepository) DeleteOrg(arg1 context.Context, arg2 authorization.In return fakeReturns.result1 } -func (fake *OrgRepository) DeleteOrgCallCount() int { +func (fake *CFOrgRepository) DeleteOrgCallCount() int { fake.deleteOrgMutex.RLock() defer fake.deleteOrgMutex.RUnlock() return len(fake.deleteOrgArgsForCall) } -func (fake *OrgRepository) DeleteOrgCalls(stub func(context.Context, authorization.Info, repositories.DeleteOrgMessage) error) { +func (fake *CFOrgRepository) DeleteOrgCalls(stub func(context.Context, authorization.Info, repositories.DeleteOrgMessage) error) { fake.deleteOrgMutex.Lock() defer fake.deleteOrgMutex.Unlock() fake.DeleteOrgStub = stub } -func (fake *OrgRepository) DeleteOrgArgsForCall(i int) (context.Context, authorization.Info, repositories.DeleteOrgMessage) { +func (fake *CFOrgRepository) DeleteOrgArgsForCall(i int) (context.Context, authorization.Info, repositories.DeleteOrgMessage) { fake.deleteOrgMutex.RLock() defer fake.deleteOrgMutex.RUnlock() argsForCall := fake.deleteOrgArgsForCall[i] return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *OrgRepository) DeleteOrgReturns(result1 error) { +func (fake *CFOrgRepository) DeleteOrgReturns(result1 error) { fake.deleteOrgMutex.Lock() defer fake.deleteOrgMutex.Unlock() fake.DeleteOrgStub = nil @@ -203,7 +218,7 @@ func (fake *OrgRepository) DeleteOrgReturns(result1 error) { }{result1} } -func (fake *OrgRepository) DeleteOrgReturnsOnCall(i int, result1 error) { +func (fake *CFOrgRepository) DeleteOrgReturnsOnCall(i int, result1 error) { fake.deleteOrgMutex.Lock() defer fake.deleteOrgMutex.Unlock() fake.DeleteOrgStub = nil @@ -217,7 +232,7 @@ func (fake *OrgRepository) DeleteOrgReturnsOnCall(i int, result1 error) { }{result1} } -func (fake *OrgRepository) GetOrg(arg1 context.Context, arg2 authorization.Info, arg3 string) (repositories.OrgRecord, error) { +func (fake *CFOrgRepository) GetOrg(arg1 context.Context, arg2 authorization.Info, arg3 string) (repositories.OrgRecord, error) { fake.getOrgMutex.Lock() ret, specificReturn := fake.getOrgReturnsOnCall[len(fake.getOrgArgsForCall)] fake.getOrgArgsForCall = append(fake.getOrgArgsForCall, struct { @@ -238,26 +253,26 @@ func (fake *OrgRepository) GetOrg(arg1 context.Context, arg2 authorization.Info, return fakeReturns.result1, fakeReturns.result2 } -func (fake *OrgRepository) GetOrgCallCount() int { +func (fake *CFOrgRepository) GetOrgCallCount() int { fake.getOrgMutex.RLock() defer fake.getOrgMutex.RUnlock() return len(fake.getOrgArgsForCall) } -func (fake *OrgRepository) GetOrgCalls(stub func(context.Context, authorization.Info, string) (repositories.OrgRecord, error)) { +func (fake *CFOrgRepository) GetOrgCalls(stub func(context.Context, authorization.Info, string) (repositories.OrgRecord, error)) { fake.getOrgMutex.Lock() defer fake.getOrgMutex.Unlock() fake.GetOrgStub = stub } -func (fake *OrgRepository) GetOrgArgsForCall(i int) (context.Context, authorization.Info, string) { +func (fake *CFOrgRepository) GetOrgArgsForCall(i int) (context.Context, authorization.Info, string) { fake.getOrgMutex.RLock() defer fake.getOrgMutex.RUnlock() argsForCall := fake.getOrgArgsForCall[i] return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *OrgRepository) GetOrgReturns(result1 repositories.OrgRecord, result2 error) { +func (fake *CFOrgRepository) GetOrgReturns(result1 repositories.OrgRecord, result2 error) { fake.getOrgMutex.Lock() defer fake.getOrgMutex.Unlock() fake.GetOrgStub = nil @@ -267,7 +282,7 @@ func (fake *OrgRepository) GetOrgReturns(result1 repositories.OrgRecord, result2 }{result1, result2} } -func (fake *OrgRepository) GetOrgReturnsOnCall(i int, result1 repositories.OrgRecord, result2 error) { +func (fake *CFOrgRepository) GetOrgReturnsOnCall(i int, result1 repositories.OrgRecord, result2 error) { fake.getOrgMutex.Lock() defer fake.getOrgMutex.Unlock() fake.GetOrgStub = nil @@ -283,7 +298,73 @@ func (fake *OrgRepository) GetOrgReturnsOnCall(i int, result1 repositories.OrgRe }{result1, result2} } -func (fake *OrgRepository) ListOrgs(arg1 context.Context, arg2 authorization.Info, arg3 repositories.ListOrgsMessage) ([]repositories.OrgRecord, error) { +func (fake *CFOrgRepository) GetOrgUnfiltered(arg1 context.Context, arg2 authorization.Info, arg3 string) (repositories.OrgRecord, error) { + fake.getOrgUnfilteredMutex.Lock() + ret, specificReturn := fake.getOrgUnfilteredReturnsOnCall[len(fake.getOrgUnfilteredArgsForCall)] + fake.getOrgUnfilteredArgsForCall = append(fake.getOrgUnfilteredArgsForCall, struct { + arg1 context.Context + arg2 authorization.Info + arg3 string + }{arg1, arg2, arg3}) + stub := fake.GetOrgUnfilteredStub + fakeReturns := fake.getOrgUnfilteredReturns + fake.recordInvocation("GetOrgUnfiltered", []interface{}{arg1, arg2, arg3}) + fake.getOrgUnfilteredMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *CFOrgRepository) GetOrgUnfilteredCallCount() int { + fake.getOrgUnfilteredMutex.RLock() + defer fake.getOrgUnfilteredMutex.RUnlock() + return len(fake.getOrgUnfilteredArgsForCall) +} + +func (fake *CFOrgRepository) GetOrgUnfilteredCalls(stub func(context.Context, authorization.Info, string) (repositories.OrgRecord, error)) { + fake.getOrgUnfilteredMutex.Lock() + defer fake.getOrgUnfilteredMutex.Unlock() + fake.GetOrgUnfilteredStub = stub +} + +func (fake *CFOrgRepository) GetOrgUnfilteredArgsForCall(i int) (context.Context, authorization.Info, string) { + fake.getOrgUnfilteredMutex.RLock() + defer fake.getOrgUnfilteredMutex.RUnlock() + argsForCall := fake.getOrgUnfilteredArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *CFOrgRepository) GetOrgUnfilteredReturns(result1 repositories.OrgRecord, result2 error) { + fake.getOrgUnfilteredMutex.Lock() + defer fake.getOrgUnfilteredMutex.Unlock() + fake.GetOrgUnfilteredStub = nil + fake.getOrgUnfilteredReturns = struct { + result1 repositories.OrgRecord + result2 error + }{result1, result2} +} + +func (fake *CFOrgRepository) GetOrgUnfilteredReturnsOnCall(i int, result1 repositories.OrgRecord, result2 error) { + fake.getOrgUnfilteredMutex.Lock() + defer fake.getOrgUnfilteredMutex.Unlock() + fake.GetOrgUnfilteredStub = nil + if fake.getOrgUnfilteredReturnsOnCall == nil { + fake.getOrgUnfilteredReturnsOnCall = make(map[int]struct { + result1 repositories.OrgRecord + result2 error + }) + } + fake.getOrgUnfilteredReturnsOnCall[i] = struct { + result1 repositories.OrgRecord + result2 error + }{result1, result2} +} + +func (fake *CFOrgRepository) ListOrgs(arg1 context.Context, arg2 authorization.Info, arg3 repositories.ListOrgsMessage) ([]repositories.OrgRecord, error) { fake.listOrgsMutex.Lock() ret, specificReturn := fake.listOrgsReturnsOnCall[len(fake.listOrgsArgsForCall)] fake.listOrgsArgsForCall = append(fake.listOrgsArgsForCall, struct { @@ -304,26 +385,26 @@ func (fake *OrgRepository) ListOrgs(arg1 context.Context, arg2 authorization.Inf return fakeReturns.result1, fakeReturns.result2 } -func (fake *OrgRepository) ListOrgsCallCount() int { +func (fake *CFOrgRepository) ListOrgsCallCount() int { fake.listOrgsMutex.RLock() defer fake.listOrgsMutex.RUnlock() return len(fake.listOrgsArgsForCall) } -func (fake *OrgRepository) ListOrgsCalls(stub func(context.Context, authorization.Info, repositories.ListOrgsMessage) ([]repositories.OrgRecord, error)) { +func (fake *CFOrgRepository) ListOrgsCalls(stub func(context.Context, authorization.Info, repositories.ListOrgsMessage) ([]repositories.OrgRecord, error)) { fake.listOrgsMutex.Lock() defer fake.listOrgsMutex.Unlock() fake.ListOrgsStub = stub } -func (fake *OrgRepository) ListOrgsArgsForCall(i int) (context.Context, authorization.Info, repositories.ListOrgsMessage) { +func (fake *CFOrgRepository) ListOrgsArgsForCall(i int) (context.Context, authorization.Info, repositories.ListOrgsMessage) { fake.listOrgsMutex.RLock() defer fake.listOrgsMutex.RUnlock() argsForCall := fake.listOrgsArgsForCall[i] return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *OrgRepository) ListOrgsReturns(result1 []repositories.OrgRecord, result2 error) { +func (fake *CFOrgRepository) ListOrgsReturns(result1 []repositories.OrgRecord, result2 error) { fake.listOrgsMutex.Lock() defer fake.listOrgsMutex.Unlock() fake.ListOrgsStub = nil @@ -333,7 +414,7 @@ func (fake *OrgRepository) ListOrgsReturns(result1 []repositories.OrgRecord, res }{result1, result2} } -func (fake *OrgRepository) ListOrgsReturnsOnCall(i int, result1 []repositories.OrgRecord, result2 error) { +func (fake *CFOrgRepository) ListOrgsReturnsOnCall(i int, result1 []repositories.OrgRecord, result2 error) { fake.listOrgsMutex.Lock() defer fake.listOrgsMutex.Unlock() fake.ListOrgsStub = nil @@ -349,7 +430,7 @@ func (fake *OrgRepository) ListOrgsReturnsOnCall(i int, result1 []repositories.O }{result1, result2} } -func (fake *OrgRepository) PatchOrgMetadata(arg1 context.Context, arg2 authorization.Info, arg3 repositories.PatchOrgMetadataMessage) (repositories.OrgRecord, error) { +func (fake *CFOrgRepository) PatchOrgMetadata(arg1 context.Context, arg2 authorization.Info, arg3 repositories.PatchOrgMetadataMessage) (repositories.OrgRecord, error) { fake.patchOrgMetadataMutex.Lock() ret, specificReturn := fake.patchOrgMetadataReturnsOnCall[len(fake.patchOrgMetadataArgsForCall)] fake.patchOrgMetadataArgsForCall = append(fake.patchOrgMetadataArgsForCall, struct { @@ -370,26 +451,26 @@ func (fake *OrgRepository) PatchOrgMetadata(arg1 context.Context, arg2 authoriza return fakeReturns.result1, fakeReturns.result2 } -func (fake *OrgRepository) PatchOrgMetadataCallCount() int { +func (fake *CFOrgRepository) PatchOrgMetadataCallCount() int { fake.patchOrgMetadataMutex.RLock() defer fake.patchOrgMetadataMutex.RUnlock() return len(fake.patchOrgMetadataArgsForCall) } -func (fake *OrgRepository) PatchOrgMetadataCalls(stub func(context.Context, authorization.Info, repositories.PatchOrgMetadataMessage) (repositories.OrgRecord, error)) { +func (fake *CFOrgRepository) PatchOrgMetadataCalls(stub func(context.Context, authorization.Info, repositories.PatchOrgMetadataMessage) (repositories.OrgRecord, error)) { fake.patchOrgMetadataMutex.Lock() defer fake.patchOrgMetadataMutex.Unlock() fake.PatchOrgMetadataStub = stub } -func (fake *OrgRepository) PatchOrgMetadataArgsForCall(i int) (context.Context, authorization.Info, repositories.PatchOrgMetadataMessage) { +func (fake *CFOrgRepository) PatchOrgMetadataArgsForCall(i int) (context.Context, authorization.Info, repositories.PatchOrgMetadataMessage) { fake.patchOrgMetadataMutex.RLock() defer fake.patchOrgMetadataMutex.RUnlock() argsForCall := fake.patchOrgMetadataArgsForCall[i] return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *OrgRepository) PatchOrgMetadataReturns(result1 repositories.OrgRecord, result2 error) { +func (fake *CFOrgRepository) PatchOrgMetadataReturns(result1 repositories.OrgRecord, result2 error) { fake.patchOrgMetadataMutex.Lock() defer fake.patchOrgMetadataMutex.Unlock() fake.PatchOrgMetadataStub = nil @@ -399,7 +480,7 @@ func (fake *OrgRepository) PatchOrgMetadataReturns(result1 repositories.OrgRecor }{result1, result2} } -func (fake *OrgRepository) PatchOrgMetadataReturnsOnCall(i int, result1 repositories.OrgRecord, result2 error) { +func (fake *CFOrgRepository) PatchOrgMetadataReturnsOnCall(i int, result1 repositories.OrgRecord, result2 error) { fake.patchOrgMetadataMutex.Lock() defer fake.patchOrgMetadataMutex.Unlock() fake.PatchOrgMetadataStub = nil @@ -415,7 +496,7 @@ func (fake *OrgRepository) PatchOrgMetadataReturnsOnCall(i int, result1 reposito }{result1, result2} } -func (fake *OrgRepository) Invocations() map[string][][]interface{} { +func (fake *CFOrgRepository) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() fake.createOrgMutex.RLock() @@ -424,6 +505,8 @@ func (fake *OrgRepository) Invocations() map[string][][]interface{} { defer fake.deleteOrgMutex.RUnlock() fake.getOrgMutex.RLock() defer fake.getOrgMutex.RUnlock() + fake.getOrgUnfilteredMutex.RLock() + defer fake.getOrgUnfilteredMutex.RUnlock() fake.listOrgsMutex.RLock() defer fake.listOrgsMutex.RUnlock() fake.patchOrgMetadataMutex.RLock() @@ -435,7 +518,7 @@ func (fake *OrgRepository) Invocations() map[string][][]interface{} { return copiedInvocations } -func (fake *OrgRepository) recordInvocation(key string, args []interface{}) { +func (fake *CFOrgRepository) recordInvocation(key string, args []interface{}) { fake.invocationsMutex.Lock() defer fake.invocationsMutex.Unlock() if fake.invocations == nil { @@ -447,4 +530,4 @@ func (fake *OrgRepository) recordInvocation(key string, args []interface{}) { fake.invocations[key] = append(fake.invocations[key], args) } -var _ handlers.CFOrgRepository = new(OrgRepository) +var _ handlers.CFOrgRepository = new(CFOrgRepository) diff --git a/api/handlers/fake/cfspace_repository.go b/api/handlers/fake/cfspace_repository.go index 92f271b17..8cfab6569 100644 --- a/api/handlers/fake/cfspace_repository.go +++ b/api/handlers/fake/cfspace_repository.go @@ -69,6 +69,21 @@ type CFSpaceRepository struct { result1 []repositories.SpaceRecord result2 error } + PatchSpaceMetadataStub func(context.Context, authorization.Info, repositories.PatchSpaceMetadataMessage) (repositories.SpaceRecord, error) + patchSpaceMetadataMutex sync.RWMutex + patchSpaceMetadataArgsForCall []struct { + arg1 context.Context + arg2 authorization.Info + arg3 repositories.PatchSpaceMetadataMessage + } + patchSpaceMetadataReturns struct { + result1 repositories.SpaceRecord + result2 error + } + patchSpaceMetadataReturnsOnCall map[int]struct { + result1 repositories.SpaceRecord + result2 error + } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } @@ -334,6 +349,72 @@ func (fake *CFSpaceRepository) ListSpacesReturnsOnCall(i int, result1 []reposito }{result1, result2} } +func (fake *CFSpaceRepository) PatchSpaceMetadata(arg1 context.Context, arg2 authorization.Info, arg3 repositories.PatchSpaceMetadataMessage) (repositories.SpaceRecord, error) { + fake.patchSpaceMetadataMutex.Lock() + ret, specificReturn := fake.patchSpaceMetadataReturnsOnCall[len(fake.patchSpaceMetadataArgsForCall)] + fake.patchSpaceMetadataArgsForCall = append(fake.patchSpaceMetadataArgsForCall, struct { + arg1 context.Context + arg2 authorization.Info + arg3 repositories.PatchSpaceMetadataMessage + }{arg1, arg2, arg3}) + stub := fake.PatchSpaceMetadataStub + fakeReturns := fake.patchSpaceMetadataReturns + fake.recordInvocation("PatchSpaceMetadata", []interface{}{arg1, arg2, arg3}) + fake.patchSpaceMetadataMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *CFSpaceRepository) PatchSpaceMetadataCallCount() int { + fake.patchSpaceMetadataMutex.RLock() + defer fake.patchSpaceMetadataMutex.RUnlock() + return len(fake.patchSpaceMetadataArgsForCall) +} + +func (fake *CFSpaceRepository) PatchSpaceMetadataCalls(stub func(context.Context, authorization.Info, repositories.PatchSpaceMetadataMessage) (repositories.SpaceRecord, error)) { + fake.patchSpaceMetadataMutex.Lock() + defer fake.patchSpaceMetadataMutex.Unlock() + fake.PatchSpaceMetadataStub = stub +} + +func (fake *CFSpaceRepository) PatchSpaceMetadataArgsForCall(i int) (context.Context, authorization.Info, repositories.PatchSpaceMetadataMessage) { + fake.patchSpaceMetadataMutex.RLock() + defer fake.patchSpaceMetadataMutex.RUnlock() + argsForCall := fake.patchSpaceMetadataArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *CFSpaceRepository) PatchSpaceMetadataReturns(result1 repositories.SpaceRecord, result2 error) { + fake.patchSpaceMetadataMutex.Lock() + defer fake.patchSpaceMetadataMutex.Unlock() + fake.PatchSpaceMetadataStub = nil + fake.patchSpaceMetadataReturns = struct { + result1 repositories.SpaceRecord + result2 error + }{result1, result2} +} + +func (fake *CFSpaceRepository) PatchSpaceMetadataReturnsOnCall(i int, result1 repositories.SpaceRecord, result2 error) { + fake.patchSpaceMetadataMutex.Lock() + defer fake.patchSpaceMetadataMutex.Unlock() + fake.PatchSpaceMetadataStub = nil + if fake.patchSpaceMetadataReturnsOnCall == nil { + fake.patchSpaceMetadataReturnsOnCall = make(map[int]struct { + result1 repositories.SpaceRecord + result2 error + }) + } + fake.patchSpaceMetadataReturnsOnCall[i] = struct { + result1 repositories.SpaceRecord + result2 error + }{result1, result2} +} + func (fake *CFSpaceRepository) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() @@ -345,6 +426,8 @@ func (fake *CFSpaceRepository) Invocations() map[string][][]interface{} { defer fake.getSpaceMutex.RUnlock() fake.listSpacesMutex.RLock() defer fake.listSpacesMutex.RUnlock() + fake.patchSpaceMetadataMutex.RLock() + defer fake.patchSpaceMetadataMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} for key, value := range fake.invocations { copiedInvocations[key] = value diff --git a/api/handlers/fake/space_repository.go b/api/handlers/fake/space_repository.go deleted file mode 100644 index 4d797f670..000000000 --- a/api/handlers/fake/space_repository.go +++ /dev/null @@ -1,450 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package fake - -import ( - "context" - "sync" - - "code.cloudfoundry.org/korifi/api/authorization" - "code.cloudfoundry.org/korifi/api/handlers" - "code.cloudfoundry.org/korifi/api/repositories" -) - -type SpaceRepository struct { - CreateSpaceStub func(context.Context, authorization.Info, repositories.CreateSpaceMessage) (repositories.SpaceRecord, error) - createSpaceMutex sync.RWMutex - createSpaceArgsForCall []struct { - arg1 context.Context - arg2 authorization.Info - arg3 repositories.CreateSpaceMessage - } - createSpaceReturns struct { - result1 repositories.SpaceRecord - result2 error - } - createSpaceReturnsOnCall map[int]struct { - result1 repositories.SpaceRecord - result2 error - } - DeleteSpaceStub func(context.Context, authorization.Info, repositories.DeleteSpaceMessage) error - deleteSpaceMutex sync.RWMutex - deleteSpaceArgsForCall []struct { - arg1 context.Context - arg2 authorization.Info - arg3 repositories.DeleteSpaceMessage - } - deleteSpaceReturns struct { - result1 error - } - deleteSpaceReturnsOnCall map[int]struct { - result1 error - } - GetSpaceStub func(context.Context, authorization.Info, string) (repositories.SpaceRecord, error) - getSpaceMutex sync.RWMutex - getSpaceArgsForCall []struct { - arg1 context.Context - arg2 authorization.Info - arg3 string - } - getSpaceReturns struct { - result1 repositories.SpaceRecord - result2 error - } - getSpaceReturnsOnCall map[int]struct { - result1 repositories.SpaceRecord - result2 error - } - ListSpacesStub func(context.Context, authorization.Info, repositories.ListSpacesMessage) ([]repositories.SpaceRecord, error) - listSpacesMutex sync.RWMutex - listSpacesArgsForCall []struct { - arg1 context.Context - arg2 authorization.Info - arg3 repositories.ListSpacesMessage - } - listSpacesReturns struct { - result1 []repositories.SpaceRecord - result2 error - } - listSpacesReturnsOnCall map[int]struct { - result1 []repositories.SpaceRecord - result2 error - } - PatchSpaceMetadataStub func(context.Context, authorization.Info, repositories.PatchSpaceMetadataMessage) (repositories.SpaceRecord, error) - patchSpaceMetadataMutex sync.RWMutex - patchSpaceMetadataArgsForCall []struct { - arg1 context.Context - arg2 authorization.Info - arg3 repositories.PatchSpaceMetadataMessage - } - patchSpaceMetadataReturns struct { - result1 repositories.SpaceRecord - result2 error - } - patchSpaceMetadataReturnsOnCall map[int]struct { - result1 repositories.SpaceRecord - result2 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *SpaceRepository) CreateSpace(arg1 context.Context, arg2 authorization.Info, arg3 repositories.CreateSpaceMessage) (repositories.SpaceRecord, error) { - fake.createSpaceMutex.Lock() - ret, specificReturn := fake.createSpaceReturnsOnCall[len(fake.createSpaceArgsForCall)] - fake.createSpaceArgsForCall = append(fake.createSpaceArgsForCall, struct { - arg1 context.Context - arg2 authorization.Info - arg3 repositories.CreateSpaceMessage - }{arg1, arg2, arg3}) - stub := fake.CreateSpaceStub - fakeReturns := fake.createSpaceReturns - fake.recordInvocation("CreateSpace", []interface{}{arg1, arg2, arg3}) - fake.createSpaceMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *SpaceRepository) CreateSpaceCallCount() int { - fake.createSpaceMutex.RLock() - defer fake.createSpaceMutex.RUnlock() - return len(fake.createSpaceArgsForCall) -} - -func (fake *SpaceRepository) CreateSpaceCalls(stub func(context.Context, authorization.Info, repositories.CreateSpaceMessage) (repositories.SpaceRecord, error)) { - fake.createSpaceMutex.Lock() - defer fake.createSpaceMutex.Unlock() - fake.CreateSpaceStub = stub -} - -func (fake *SpaceRepository) CreateSpaceArgsForCall(i int) (context.Context, authorization.Info, repositories.CreateSpaceMessage) { - fake.createSpaceMutex.RLock() - defer fake.createSpaceMutex.RUnlock() - argsForCall := fake.createSpaceArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *SpaceRepository) CreateSpaceReturns(result1 repositories.SpaceRecord, result2 error) { - fake.createSpaceMutex.Lock() - defer fake.createSpaceMutex.Unlock() - fake.CreateSpaceStub = nil - fake.createSpaceReturns = struct { - result1 repositories.SpaceRecord - result2 error - }{result1, result2} -} - -func (fake *SpaceRepository) CreateSpaceReturnsOnCall(i int, result1 repositories.SpaceRecord, result2 error) { - fake.createSpaceMutex.Lock() - defer fake.createSpaceMutex.Unlock() - fake.CreateSpaceStub = nil - if fake.createSpaceReturnsOnCall == nil { - fake.createSpaceReturnsOnCall = make(map[int]struct { - result1 repositories.SpaceRecord - result2 error - }) - } - fake.createSpaceReturnsOnCall[i] = struct { - result1 repositories.SpaceRecord - result2 error - }{result1, result2} -} - -func (fake *SpaceRepository) DeleteSpace(arg1 context.Context, arg2 authorization.Info, arg3 repositories.DeleteSpaceMessage) error { - fake.deleteSpaceMutex.Lock() - ret, specificReturn := fake.deleteSpaceReturnsOnCall[len(fake.deleteSpaceArgsForCall)] - fake.deleteSpaceArgsForCall = append(fake.deleteSpaceArgsForCall, struct { - arg1 context.Context - arg2 authorization.Info - arg3 repositories.DeleteSpaceMessage - }{arg1, arg2, arg3}) - stub := fake.DeleteSpaceStub - fakeReturns := fake.deleteSpaceReturns - fake.recordInvocation("DeleteSpace", []interface{}{arg1, arg2, arg3}) - fake.deleteSpaceMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *SpaceRepository) DeleteSpaceCallCount() int { - fake.deleteSpaceMutex.RLock() - defer fake.deleteSpaceMutex.RUnlock() - return len(fake.deleteSpaceArgsForCall) -} - -func (fake *SpaceRepository) DeleteSpaceCalls(stub func(context.Context, authorization.Info, repositories.DeleteSpaceMessage) error) { - fake.deleteSpaceMutex.Lock() - defer fake.deleteSpaceMutex.Unlock() - fake.DeleteSpaceStub = stub -} - -func (fake *SpaceRepository) DeleteSpaceArgsForCall(i int) (context.Context, authorization.Info, repositories.DeleteSpaceMessage) { - fake.deleteSpaceMutex.RLock() - defer fake.deleteSpaceMutex.RUnlock() - argsForCall := fake.deleteSpaceArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *SpaceRepository) DeleteSpaceReturns(result1 error) { - fake.deleteSpaceMutex.Lock() - defer fake.deleteSpaceMutex.Unlock() - fake.DeleteSpaceStub = nil - fake.deleteSpaceReturns = struct { - result1 error - }{result1} -} - -func (fake *SpaceRepository) DeleteSpaceReturnsOnCall(i int, result1 error) { - fake.deleteSpaceMutex.Lock() - defer fake.deleteSpaceMutex.Unlock() - fake.DeleteSpaceStub = nil - if fake.deleteSpaceReturnsOnCall == nil { - fake.deleteSpaceReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.deleteSpaceReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *SpaceRepository) GetSpace(arg1 context.Context, arg2 authorization.Info, arg3 string) (repositories.SpaceRecord, error) { - fake.getSpaceMutex.Lock() - ret, specificReturn := fake.getSpaceReturnsOnCall[len(fake.getSpaceArgsForCall)] - fake.getSpaceArgsForCall = append(fake.getSpaceArgsForCall, struct { - arg1 context.Context - arg2 authorization.Info - arg3 string - }{arg1, arg2, arg3}) - stub := fake.GetSpaceStub - fakeReturns := fake.getSpaceReturns - fake.recordInvocation("GetSpace", []interface{}{arg1, arg2, arg3}) - fake.getSpaceMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *SpaceRepository) GetSpaceCallCount() int { - fake.getSpaceMutex.RLock() - defer fake.getSpaceMutex.RUnlock() - return len(fake.getSpaceArgsForCall) -} - -func (fake *SpaceRepository) GetSpaceCalls(stub func(context.Context, authorization.Info, string) (repositories.SpaceRecord, error)) { - fake.getSpaceMutex.Lock() - defer fake.getSpaceMutex.Unlock() - fake.GetSpaceStub = stub -} - -func (fake *SpaceRepository) GetSpaceArgsForCall(i int) (context.Context, authorization.Info, string) { - fake.getSpaceMutex.RLock() - defer fake.getSpaceMutex.RUnlock() - argsForCall := fake.getSpaceArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *SpaceRepository) GetSpaceReturns(result1 repositories.SpaceRecord, result2 error) { - fake.getSpaceMutex.Lock() - defer fake.getSpaceMutex.Unlock() - fake.GetSpaceStub = nil - fake.getSpaceReturns = struct { - result1 repositories.SpaceRecord - result2 error - }{result1, result2} -} - -func (fake *SpaceRepository) GetSpaceReturnsOnCall(i int, result1 repositories.SpaceRecord, result2 error) { - fake.getSpaceMutex.Lock() - defer fake.getSpaceMutex.Unlock() - fake.GetSpaceStub = nil - if fake.getSpaceReturnsOnCall == nil { - fake.getSpaceReturnsOnCall = make(map[int]struct { - result1 repositories.SpaceRecord - result2 error - }) - } - fake.getSpaceReturnsOnCall[i] = struct { - result1 repositories.SpaceRecord - result2 error - }{result1, result2} -} - -func (fake *SpaceRepository) ListSpaces(arg1 context.Context, arg2 authorization.Info, arg3 repositories.ListSpacesMessage) ([]repositories.SpaceRecord, error) { - fake.listSpacesMutex.Lock() - ret, specificReturn := fake.listSpacesReturnsOnCall[len(fake.listSpacesArgsForCall)] - fake.listSpacesArgsForCall = append(fake.listSpacesArgsForCall, struct { - arg1 context.Context - arg2 authorization.Info - arg3 repositories.ListSpacesMessage - }{arg1, arg2, arg3}) - stub := fake.ListSpacesStub - fakeReturns := fake.listSpacesReturns - fake.recordInvocation("ListSpaces", []interface{}{arg1, arg2, arg3}) - fake.listSpacesMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *SpaceRepository) ListSpacesCallCount() int { - fake.listSpacesMutex.RLock() - defer fake.listSpacesMutex.RUnlock() - return len(fake.listSpacesArgsForCall) -} - -func (fake *SpaceRepository) ListSpacesCalls(stub func(context.Context, authorization.Info, repositories.ListSpacesMessage) ([]repositories.SpaceRecord, error)) { - fake.listSpacesMutex.Lock() - defer fake.listSpacesMutex.Unlock() - fake.ListSpacesStub = stub -} - -func (fake *SpaceRepository) ListSpacesArgsForCall(i int) (context.Context, authorization.Info, repositories.ListSpacesMessage) { - fake.listSpacesMutex.RLock() - defer fake.listSpacesMutex.RUnlock() - argsForCall := fake.listSpacesArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *SpaceRepository) ListSpacesReturns(result1 []repositories.SpaceRecord, result2 error) { - fake.listSpacesMutex.Lock() - defer fake.listSpacesMutex.Unlock() - fake.ListSpacesStub = nil - fake.listSpacesReturns = struct { - result1 []repositories.SpaceRecord - result2 error - }{result1, result2} -} - -func (fake *SpaceRepository) ListSpacesReturnsOnCall(i int, result1 []repositories.SpaceRecord, result2 error) { - fake.listSpacesMutex.Lock() - defer fake.listSpacesMutex.Unlock() - fake.ListSpacesStub = nil - if fake.listSpacesReturnsOnCall == nil { - fake.listSpacesReturnsOnCall = make(map[int]struct { - result1 []repositories.SpaceRecord - result2 error - }) - } - fake.listSpacesReturnsOnCall[i] = struct { - result1 []repositories.SpaceRecord - result2 error - }{result1, result2} -} - -func (fake *SpaceRepository) PatchSpaceMetadata(arg1 context.Context, arg2 authorization.Info, arg3 repositories.PatchSpaceMetadataMessage) (repositories.SpaceRecord, error) { - fake.patchSpaceMetadataMutex.Lock() - ret, specificReturn := fake.patchSpaceMetadataReturnsOnCall[len(fake.patchSpaceMetadataArgsForCall)] - fake.patchSpaceMetadataArgsForCall = append(fake.patchSpaceMetadataArgsForCall, struct { - arg1 context.Context - arg2 authorization.Info - arg3 repositories.PatchSpaceMetadataMessage - }{arg1, arg2, arg3}) - stub := fake.PatchSpaceMetadataStub - fakeReturns := fake.patchSpaceMetadataReturns - fake.recordInvocation("PatchSpaceMetadata", []interface{}{arg1, arg2, arg3}) - fake.patchSpaceMetadataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *SpaceRepository) PatchSpaceMetadataCallCount() int { - fake.patchSpaceMetadataMutex.RLock() - defer fake.patchSpaceMetadataMutex.RUnlock() - return len(fake.patchSpaceMetadataArgsForCall) -} - -func (fake *SpaceRepository) PatchSpaceMetadataCalls(stub func(context.Context, authorization.Info, repositories.PatchSpaceMetadataMessage) (repositories.SpaceRecord, error)) { - fake.patchSpaceMetadataMutex.Lock() - defer fake.patchSpaceMetadataMutex.Unlock() - fake.PatchSpaceMetadataStub = stub -} - -func (fake *SpaceRepository) PatchSpaceMetadataArgsForCall(i int) (context.Context, authorization.Info, repositories.PatchSpaceMetadataMessage) { - fake.patchSpaceMetadataMutex.RLock() - defer fake.patchSpaceMetadataMutex.RUnlock() - argsForCall := fake.patchSpaceMetadataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *SpaceRepository) PatchSpaceMetadataReturns(result1 repositories.SpaceRecord, result2 error) { - fake.patchSpaceMetadataMutex.Lock() - defer fake.patchSpaceMetadataMutex.Unlock() - fake.PatchSpaceMetadataStub = nil - fake.patchSpaceMetadataReturns = struct { - result1 repositories.SpaceRecord - result2 error - }{result1, result2} -} - -func (fake *SpaceRepository) PatchSpaceMetadataReturnsOnCall(i int, result1 repositories.SpaceRecord, result2 error) { - fake.patchSpaceMetadataMutex.Lock() - defer fake.patchSpaceMetadataMutex.Unlock() - fake.PatchSpaceMetadataStub = nil - if fake.patchSpaceMetadataReturnsOnCall == nil { - fake.patchSpaceMetadataReturnsOnCall = make(map[int]struct { - result1 repositories.SpaceRecord - result2 error - }) - } - fake.patchSpaceMetadataReturnsOnCall[i] = struct { - result1 repositories.SpaceRecord - result2 error - }{result1, result2} -} - -func (fake *SpaceRepository) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.createSpaceMutex.RLock() - defer fake.createSpaceMutex.RUnlock() - fake.deleteSpaceMutex.RLock() - defer fake.deleteSpaceMutex.RUnlock() - fake.getSpaceMutex.RLock() - defer fake.getSpaceMutex.RUnlock() - fake.listSpacesMutex.RLock() - defer fake.listSpacesMutex.RUnlock() - fake.patchSpaceMetadataMutex.RLock() - defer fake.patchSpaceMetadataMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *SpaceRepository) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} - -var _ handlers.SpaceRepository = new(SpaceRepository) diff --git a/api/handlers/job.go b/api/handlers/job.go index 248506936..fd1e42483 100644 --- a/api/handlers/job.go +++ b/api/handlers/job.go @@ -72,7 +72,7 @@ func (h *Job) get(r *http.Request) (*routing.Response, error) { case appDeletePrefix, routeDeletePrefix, domainDeletePrefix, roleDeletePrefix: jobResponse = presenter.ForJob(jobGUID, []presenter.JobResponseError{}, presenter.StateComplete, jobType, h.serverURL) case orgDeletePrefix, spaceDeletePrefix: - jobResponse, err = h.handleDeleteJob(r.Context(), resourceGUID, jobGUID, jobType) + jobResponse, err = h.handleDeleteJob(r.Context(), jobType, resourceGUID) if err != nil { return nil, err } @@ -87,52 +87,65 @@ func (h *Job) get(r *http.Request) (*routing.Response, error) { return routing.NewResponse(http.StatusOK).WithBody(jobResponse), nil } -func (h *Job) handleDeleteJob(ctx context.Context, resourceGUID, jobGUID, jobType string) (presenter.JobResponse, error) { +func (h *Job) handleDeleteJob(ctx context.Context, jobType, resourceGUID string) (presenter.JobResponse, error) { authInfo, _ := authorization.InfoFromContext(ctx) + jobGUID := jobType + presenter.JobGUIDDelimiter + resourceGUID log := logr.FromContextOrDiscard(ctx).WithName("handlers.job.get.handleDeleteJob") var ( org repositories.OrgRecord space repositories.SpaceRecord err error - resourceName string resourceType string deletedAt string ) - switch jobType { - case orgDeletePrefix: - org, err = h.orgRepo.GetOrg(ctx, authInfo, resourceGUID) - resourceName = org.Name - resourceType = "Org" - deletedAt = org.DeletedAt - case spaceDeletePrefix: - space, err = h.spaceRepo.GetSpace(ctx, authInfo, resourceGUID) - resourceName = space.Name - resourceType = "Space" - deletedAt = space.DeletedAt - } + for retries := 0; retries < 40; retries++ { + switch jobType { + case orgDeletePrefix: + org, err = h.orgRepo.GetOrgUnfiltered(ctx, authInfo, resourceGUID) + resourceType = "Org" + deletedAt = org.DeletedAt + case spaceDeletePrefix: + space, err = h.spaceRepo.GetSpace(ctx, authInfo, resourceGUID) + resourceType = "Space" + deletedAt = space.DeletedAt + } - if err != nil { - switch err.(type) { - case apierrors.NotFoundError, apierrors.ForbiddenError: - return presenter.ForJob( - jobGUID, - []presenter.JobResponseError{}, - presenter.StateComplete, - jobType, - h.serverURL, - ), nil - default: - return presenter.JobResponse{}, apierrors.LogAndReturn( - log, - err, - "failed to fetch "+resourceType+" from Kubernetes", - resourceType+"GUID", resourceGUID, - ) + if err != nil { + switch err.(type) { + case apierrors.NotFoundError, apierrors.ForbiddenError: + return presenter.ForJob(jobGUID, + []presenter.JobResponseError{}, + presenter.StateComplete, + jobType, + h.serverURL, + ), nil + default: + return presenter.JobResponse{}, apierrors.LogAndReturn( + log, + err, + "failed to fetch "+resourceType+" from Kubernetes", + resourceType+"GUID", resourceGUID, + ) + } } + + if deletedAt != "" { + break + } + + log.V(1).Info("Waiting for deletion timestamp", resourceType+"GUID", resourceGUID) + time.Sleep(500 * time.Millisecond) } + return h.handleDeleteJobResponse(ctx, deletedAt, jobType, resourceGUID, resourceType) +} + +func (h *Job) handleDeleteJobResponse(ctx context.Context, deletedAt, jobType, resourceGUID, resourceType string) (presenter.JobResponse, error) { + jobGUID := jobType + presenter.JobGUIDDelimiter + resourceGUID + log := logr.FromContextOrDiscard(ctx).WithName("handlers.job.get.handleDeleteJobResponse") + if deletedAt == "" { return presenter.JobResponse{}, apierrors.LogAndReturn( log, @@ -147,8 +160,8 @@ func (h *Job) handleDeleteJob(ctx context.Context, resourceGUID, jobGUID, jobTyp return presenter.JobResponse{}, apierrors.LogAndReturn( log, err, - "failed to parse "+resourceType+" deletion time", - "name", resourceName, + "failed to parse deletion time", + resourceType+"GUID", resourceGUID, "timestamp", deletedAt, ) } @@ -161,19 +174,19 @@ func (h *Job) handleDeleteJob(ctx context.Context, resourceGUID, jobGUID, jobTyp jobType, h.serverURL, ), nil - } else { - return presenter.ForJob( - jobGUID, - []presenter.JobResponseError{{ - Code: 10008, - Detail: fmt.Sprintf("%s deletion timed out. Check for remaining resources in the %q namespace", resourceType, resourceGUID), - Title: "CF-UnprocessableEntity", - }}, - presenter.StateFailed, - jobType, - h.serverURL, - ), nil } + + return presenter.ForJob( + jobGUID, + []presenter.JobResponseError{{ + Code: 10008, + Detail: fmt.Sprintf("%s deletion timed out. Check for remaining resources in the %q namespace", resourceType, resourceGUID), + Title: "CF-UnprocessableEntity", + }}, + presenter.StateFailed, + jobType, + h.serverURL, + ), nil } func (h *Job) UnauthenticatedRoutes() []routing.Route { diff --git a/api/handlers/job_test.go b/api/handlers/job_test.go index 9dbff7cdf..51157679c 100644 --- a/api/handlers/job_test.go +++ b/api/handlers/job_test.go @@ -23,15 +23,15 @@ var _ = Describe("Job", func() { spaceGUID string jobGUID string req *http.Request - orgRepo *fake.OrgRepository - spaceRepo *fake.SpaceRepository + orgRepo *fake.CFOrgRepository + spaceRepo *fake.CFSpaceRepository ) BeforeEach(func() { spaceGUID = uuid.NewString() - orgRepo = new(fake.OrgRepository) - spaceRepo = new(fake.SpaceRepository) + orgRepo = new(fake.CFOrgRepository) + spaceRepo = new(fake.CFSpaceRepository) apiHandler := handlers.NewJob(*serverURL, orgRepo, spaceRepo) routerBuilder.LoadRoutes(apiHandler) }) @@ -102,7 +102,7 @@ var _ = Describe("Job", func() { When("the org deletion is in progress", func() { BeforeEach(func() { - orgRepo.GetOrgReturns(repositories.OrgRecord{ + orgRepo.GetOrgUnfilteredReturns(repositories.OrgRecord{ GUID: "cf-org-guid", DeletedAt: time.Now().Format(time.RFC3339Nano), }, nil) @@ -121,7 +121,7 @@ var _ = Describe("Job", func() { When("the org does not exist", func() { BeforeEach(func() { - orgRepo.GetOrgReturns(repositories.OrgRecord{}, apierrors.NewNotFoundError(nil, repositories.OrgResourceType)) + orgRepo.GetOrgUnfilteredReturns(repositories.OrgRecord{}, apierrors.NewNotFoundError(nil, repositories.OrgResourceType)) }) It("returns a complete status", func() { @@ -137,7 +137,7 @@ var _ = Describe("Job", func() { When("the org deletion times out", func() { BeforeEach(func() { - orgRepo.GetOrgReturns(repositories.OrgRecord{ + orgRepo.GetOrgUnfilteredReturns(repositories.OrgRecord{ GUID: "cf-org-guid", DeletedAt: (time.Now().Add(-180 * time.Second)).Format(time.RFC3339Nano), }, nil) @@ -160,7 +160,7 @@ var _ = Describe("Job", func() { When("the user does not have permission to see the org", func() { BeforeEach(func() { - orgRepo.GetOrgReturns(repositories.OrgRecord{}, apierrors.NewForbiddenError(nil, repositories.OrgResourceType)) + orgRepo.GetOrgUnfilteredReturns(repositories.OrgRecord{}, apierrors.NewForbiddenError(nil, repositories.OrgResourceType)) }) It("returns a complete status", func() { @@ -176,7 +176,7 @@ var _ = Describe("Job", func() { When("the org has not been marked for deletion", func() { BeforeEach(func() { - orgRepo.GetOrgReturns(repositories.OrgRecord{ + orgRepo.GetOrgUnfilteredReturns(repositories.OrgRecord{ GUID: resourceGUID, }, nil) }) diff --git a/api/handlers/org.go b/api/handlers/org.go index 116dcb4f7..1f9d67910 100644 --- a/api/handlers/org.go +++ b/api/handlers/org.go @@ -26,12 +26,13 @@ const ( OrgDefaultDomainPath = "/v3/organizations/{guid}/domains/default" ) -//counterfeiter:generate -o fake -fake-name OrgRepository . CFOrgRepository +//counterfeiter:generate -o fake -fake-name CFOrgRepository . CFOrgRepository type CFOrgRepository interface { CreateOrg(context.Context, authorization.Info, repositories.CreateOrgMessage) (repositories.OrgRecord, error) ListOrgs(context.Context, authorization.Info, repositories.ListOrgsMessage) ([]repositories.OrgRecord, error) DeleteOrg(context.Context, authorization.Info, repositories.DeleteOrgMessage) error GetOrg(context.Context, authorization.Info, string) (repositories.OrgRecord, error) + GetOrgUnfiltered(context.Context, authorization.Info, string) (repositories.OrgRecord, error) PatchOrgMetadata(context.Context, authorization.Info, repositories.PatchOrgMetadataMessage) (repositories.OrgRecord, error) } diff --git a/api/handlers/org_test.go b/api/handlers/org_test.go index f9b48d61f..0ad70199f 100644 --- a/api/handlers/org_test.go +++ b/api/handlers/org_test.go @@ -22,7 +22,7 @@ import ( var _ = Describe("Org", func() { var ( apiHandler *handlers.Org - orgRepo *fake.OrgRepository + orgRepo *fake.CFOrgRepository now string domainRepo *fake.CFDomainRepository requestValidator *fake.RequestValidator @@ -31,7 +31,7 @@ var _ = Describe("Org", func() { BeforeEach(func() { now = time.Unix(1631892190, 0).UTC().Format(time.RFC3339) // 2021-09-17T15:23:10Z - orgRepo = new(fake.OrgRepository) + orgRepo = new(fake.CFOrgRepository) domainRepo = new(fake.CFDomainRepository) requestValidator = new(fake.RequestValidator) diff --git a/api/handlers/route.go b/api/handlers/route.go index 7c90123ca..6ca07f646 100644 --- a/api/handlers/route.go +++ b/api/handlers/route.go @@ -40,7 +40,7 @@ type Route struct { routeRepo CFRouteRepository domainRepo CFDomainRepository appRepo CFAppRepository - spaceRepo SpaceRepository + spaceRepo CFSpaceRepository requestValidator RequestValidator } @@ -49,7 +49,7 @@ func NewRoute( routeRepo CFRouteRepository, domainRepo CFDomainRepository, appRepo CFAppRepository, - spaceRepo SpaceRepository, + spaceRepo CFSpaceRepository, requestValidator RequestValidator, ) *Route { return &Route{ diff --git a/api/handlers/route_test.go b/api/handlers/route_test.go index 4587173b3..4d358be70 100644 --- a/api/handlers/route_test.go +++ b/api/handlers/route_test.go @@ -24,7 +24,7 @@ var _ = Describe("Route", func() { routeRepo *fake.CFRouteRepository domainRepo *fake.CFDomainRepository appRepo *fake.CFAppRepository - spaceRepo *fake.SpaceRepository + spaceRepo *fake.CFSpaceRepository requestValidator *fake.RequestValidator requestMethod string @@ -63,7 +63,7 @@ var _ = Describe("Route", func() { appRepo = new(fake.CFAppRepository) - spaceRepo = new(fake.SpaceRepository) + spaceRepo = new(fake.CFSpaceRepository) spaceRepo.GetSpaceReturns(repositories.SpaceRecord{ Name: "test-space-guid", }, nil) diff --git a/api/handlers/service_instance.go b/api/handlers/service_instance.go index 0e55813d8..9c104a20d 100644 --- a/api/handlers/service_instance.go +++ b/api/handlers/service_instance.go @@ -36,14 +36,14 @@ type CFServiceInstanceRepository interface { type ServiceInstance struct { serverURL url.URL serviceInstanceRepo CFServiceInstanceRepository - spaceRepo SpaceRepository + spaceRepo CFSpaceRepository requestValidator RequestValidator } func NewServiceInstance( serverURL url.URL, serviceInstanceRepo CFServiceInstanceRepository, - spaceRepo SpaceRepository, + spaceRepo CFSpaceRepository, requestValidator RequestValidator, ) *ServiceInstance { return &ServiceInstance{ diff --git a/api/handlers/service_instance_test.go b/api/handlers/service_instance_test.go index d389c84b5..f1a9e7179 100644 --- a/api/handlers/service_instance_test.go +++ b/api/handlers/service_instance_test.go @@ -21,7 +21,7 @@ import ( var _ = Describe("ServiceInstance", func() { var ( serviceInstanceRepo *fake.CFServiceInstanceRepository - spaceRepo *fake.SpaceRepository + spaceRepo *fake.CFSpaceRepository requestValidator *fake.RequestValidator reqMethod string @@ -35,7 +35,7 @@ var _ = Describe("ServiceInstance", func() { SpaceGUID: "space-guid", }, nil) - spaceRepo = new(fake.SpaceRepository) + spaceRepo = new(fake.CFSpaceRepository) requestValidator = new(fake.RequestValidator) diff --git a/api/handlers/space.go b/api/handlers/space.go index acd9b850d..232a5659c 100644 --- a/api/handlers/space.go +++ b/api/handlers/space.go @@ -5,14 +5,14 @@ import ( "net/http" "net/url" - "github.com/go-logr/logr" - "code.cloudfoundry.org/korifi/api/authorization" apierrors "code.cloudfoundry.org/korifi/api/errors" "code.cloudfoundry.org/korifi/api/payloads" "code.cloudfoundry.org/korifi/api/presenter" "code.cloudfoundry.org/korifi/api/repositories" "code.cloudfoundry.org/korifi/api/routing" + + "github.com/go-logr/logr" ) const ( @@ -20,9 +20,9 @@ const ( SpacePath = "/v3/spaces/{guid}" ) -//counterfeiter:generate -o fake -fake-name SpaceRepository . SpaceRepository +//counterfeiter:generate -o fake -fake-name CFSpaceRepository . CFSpaceRepository -type SpaceRepository interface { +type CFSpaceRepository interface { CreateSpace(context.Context, authorization.Info, repositories.CreateSpaceMessage) (repositories.SpaceRecord, error) ListSpaces(context.Context, authorization.Info, repositories.ListSpacesMessage) ([]repositories.SpaceRecord, error) GetSpace(context.Context, authorization.Info, string) (repositories.SpaceRecord, error) @@ -31,12 +31,12 @@ type SpaceRepository interface { } type Space struct { - spaceRepo SpaceRepository + spaceRepo CFSpaceRepository apiBaseURL url.URL requestValidator RequestValidator } -func NewSpace(apiBaseURL url.URL, spaceRepo SpaceRepository, requestValidator RequestValidator) *Space { +func NewSpace(apiBaseURL url.URL, spaceRepo CFSpaceRepository, requestValidator RequestValidator) *Space { return &Space{ apiBaseURL: apiBaseURL, spaceRepo: spaceRepo, diff --git a/api/handlers/space_manifest.go b/api/handlers/space_manifest.go index f67dad352..21e67c9d3 100644 --- a/api/handlers/space_manifest.go +++ b/api/handlers/space_manifest.go @@ -5,14 +5,13 @@ import ( "net/http" "net/url" - "github.com/go-logr/logr" - "code.cloudfoundry.org/korifi/api/authorization" apierrors "code.cloudfoundry.org/korifi/api/errors" "code.cloudfoundry.org/korifi/api/payloads" "code.cloudfoundry.org/korifi/api/presenter" - "code.cloudfoundry.org/korifi/api/repositories" "code.cloudfoundry.org/korifi/api/routing" + + "github.com/go-logr/logr" ) const ( @@ -20,15 +19,6 @@ const ( SpaceManifestDiffPath = "/v3/spaces/{spaceGUID}/manifest_diff" ) -//counterfeiter:generate -o fake -fake-name CFSpaceRepository . CFSpaceRepository - -type CFSpaceRepository interface { - CreateSpace(context.Context, authorization.Info, repositories.CreateSpaceMessage) (repositories.SpaceRecord, error) - ListSpaces(context.Context, authorization.Info, repositories.ListSpacesMessage) ([]repositories.SpaceRecord, error) - GetSpace(context.Context, authorization.Info, string) (repositories.SpaceRecord, error) - DeleteSpace(context.Context, authorization.Info, repositories.DeleteSpaceMessage) error -} - type SpaceManifest struct { serverURL url.URL manifestApplier ManifestApplier diff --git a/api/handlers/space_test.go b/api/handlers/space_test.go index f334e86c7..c48a9a55c 100644 --- a/api/handlers/space_test.go +++ b/api/handlers/space_test.go @@ -21,7 +21,7 @@ import ( var _ = Describe("Space", func() { var ( apiHandler *handlers.Space - spaceRepo *fake.SpaceRepository + spaceRepo *fake.CFSpaceRepository requestValidator *fake.RequestValidator requestMethod string requestPath string @@ -31,7 +31,7 @@ var _ = Describe("Space", func() { requestPath = "/v3/spaces" requestValidator = new(fake.RequestValidator) - spaceRepo = new(fake.SpaceRepository) + spaceRepo = new(fake.CFSpaceRepository) spaceRepo.GetSpaceReturns(repositories.SpaceRecord{ Name: "the-space", GUID: "the-space-guid", diff --git a/api/repositories/org_repository.go b/api/repositories/org_repository.go index d9070f250..82511b27c 100644 --- a/api/repositories/org_repository.go +++ b/api/repositories/org_repository.go @@ -205,6 +205,21 @@ func (r *OrgRepo) GetOrg(ctx context.Context, info authorization.Info, orgGUID s return orgRecords[0], nil } +func (r *OrgRepo) GetOrgUnfiltered(ctx context.Context, info authorization.Info, orgGUID string) (OrgRecord, error) { + userClient, err := r.userClientFactory.BuildClient(info) + if err != nil { + return OrgRecord{}, fmt.Errorf("get-org failed to build user client: %w", err) + } + + cfOrg := new(korifiv1alpha1.CFOrg) + err = userClient.Get(ctx, client.ObjectKey{Namespace: r.rootNamespace, Name: orgGUID}, cfOrg) + if err != nil { + return OrgRecord{}, apierrors.FromK8sError(err, OrgResourceType) + } + + return cfOrgToOrgRecord(*cfOrg), nil +} + func (r *OrgRepo) DeleteOrg(ctx context.Context, info authorization.Info, message DeleteOrgMessage) error { userClient, err := r.userClientFactory.BuildClient(info) if err != nil { diff --git a/api/repositories/org_repository_test.go b/api/repositories/org_repository_test.go index 716e49aae..ba594b8b1 100644 --- a/api/repositories/org_repository_test.go +++ b/api/repositories/org_repository_test.go @@ -343,6 +343,13 @@ var _ = Describe("OrgRepository", func() { }) }) + When("the user does not have a role binding in the org", func() { + It("errors", func() { + _, err := orgRepo.GetOrg(ctx, authInfo, "the-org") + Expect(err).To(matchers.WrapErrorAssignableToTypeOf(apierrors.NotFoundError{})) + }) + }) + When("the org isn't found", func() { It("errors", func() { _, err := orgRepo.GetOrg(ctx, authInfo, "non-existent-org") @@ -351,6 +358,43 @@ var _ = Describe("OrgRepository", func() { }) }) + Describe("GetOrgUnfiltered", func() { + var cfOrg *korifiv1alpha1.CFOrg + + BeforeEach(func() { + cfOrg = createOrgWithCleanup(ctx, prefixedGUID("the-org")) + Expect(k8s.PatchResource(ctx, k8sClient, cfOrg, func() { + cfOrg.Labels = map[string]string{ + "test-label-key": "test-label-val", + } + cfOrg.Annotations = map[string]string{ + "test-annotation-key": "test-annotation-val", + } + })).To(Succeed()) + }) + + When("the org exists", func() { + BeforeEach(func() { + createRoleBinding(ctx, userName, orgUserRole.Name, cfOrg.Name) + }) + + It("gets the org", func() { + orgRecord, err := orgRepo.GetOrgUnfiltered(ctx, authInfo, cfOrg.Name) + Expect(err).NotTo(HaveOccurred()) + Expect(orgRecord.Name).To(Equal(cfOrg.Spec.DisplayName)) + Expect(orgRecord.Labels).To(Equal(map[string]string{"test-label-key": "test-label-val"})) + Expect(orgRecord.Annotations).To(Equal(map[string]string{"test-annotation-key": "test-annotation-val"})) + }) + }) + + When("the org isn't found", func() { + It("errors", func() { + _, err := orgRepo.GetOrgUnfiltered(ctx, authInfo, "non-existent-org") + Expect(err).To(matchers.WrapErrorAssignableToTypeOf(apierrors.NotFoundError{})) + }) + }) + }) + Describe("DeleteOrg", func() { var cfOrg *korifiv1alpha1.CFOrg diff --git a/api/repositories/space_repository_test.go b/api/repositories/space_repository_test.go index dcdf02cc1..b5befcaa7 100644 --- a/api/repositories/space_repository_test.go +++ b/api/repositories/space_repository_test.go @@ -412,14 +412,26 @@ var _ = Describe("SpaceRepository", func() { cfOrg = createOrgWithCleanup(ctx, "the-org") createRoleBinding(ctx, userName, orgUserRole.Name, cfOrg.Name) cfSpace = createSpaceWithCleanup(ctx, cfOrg.Name, "the-space") - createRoleBinding(ctx, userName, spaceDeveloperRole.Name, cfSpace.Name) }) - It("gets the space resource", func() { - spaceRecord, err := spaceRepo.GetSpace(ctx, authInfo, cfSpace.Name) - Expect(err).NotTo(HaveOccurred()) - Expect(spaceRecord.Name).To(Equal("the-space")) - Expect(spaceRecord.OrganizationGUID).To(Equal(cfOrg.Name)) + When("the user has a role binding in the space", func() { + BeforeEach(func() { + createRoleBinding(ctx, userName, spaceDeveloperRole.Name, cfSpace.Name) + }) + + It("gets the space resource", func() { + spaceRecord, err := spaceRepo.GetSpace(ctx, authInfo, cfSpace.Name) + Expect(err).NotTo(HaveOccurred()) + Expect(spaceRecord.Name).To(Equal("the-space")) + Expect(spaceRecord.OrganizationGUID).To(Equal(cfOrg.Name)) + }) + }) + + When("the user does not have a role binding in the space", func() { + It("errors", func() { + _, err := spaceRepo.GetSpace(ctx, authInfo, "the-space") + Expect(err).To(MatchError(ContainSubstring("not found"))) + }) }) When("the space doesn't exist", func() {