From 3d621c90e05c2265eb095300f5de10afc6cef4cd Mon Sep 17 00:00:00 2001 From: Josef Hoerandtner Date: Thu, 9 Apr 2026 12:05:36 +0200 Subject: [PATCH] feat: integrate GCR helper into RunRequestConversionHelper and update related tests --- conversion_helpers.go | 13 +++ conversion_helpers_test.go | 94 +++++++++++++++++++ generator/internal/ordinary_lrp_processor.go | 6 +- .../internal/ordinary_lrp_processor_test.go | 6 +- generator/internal/task_processor.go | 6 +- generator/internal/task_processor_test.go | 6 +- 6 files changed, 127 insertions(+), 4 deletions(-) diff --git a/conversion_helpers.go b/conversion_helpers.go index cb97dde..d1cebf6 100644 --- a/conversion_helpers.go +++ b/conversion_helpers.go @@ -13,6 +13,7 @@ import ( "code.cloudfoundry.org/bbs/models" "code.cloudfoundry.org/ecrhelper" "code.cloudfoundry.org/executor" + "code.cloudfoundry.org/gcrhelper" "code.cloudfoundry.org/routing-info/internalroutes" ) @@ -167,6 +168,7 @@ func ConvertPreloadedRootFS(rootFS string, imageLayers []*models.ImageLayer, lay type RunRequestConversionHelper struct { ECRHelper ecrhelper.ECRHelper + GCRHelper gcrhelper.GCRHelper } func (rrch RunRequestConversionHelper) NewRunRequestFromDesiredLRP( @@ -357,6 +359,17 @@ func convertImageLayers(t *models.TaskDefinition) ([]*models.CachedDependency, * } func (rrch RunRequestConversionHelper) convertCredentials(rootFS string, username string, password string) (string, string, error) { + if username == "" && password == "" { + isGCRRepo, err := rrch.GCRHelper.IsGCRRepo(rootFS) + if err != nil { + return "", "", err + } + + if isGCRRepo { + return rrch.GCRHelper.GetGCRCredentials() + } + } + isECRRepo, err := rrch.ECRHelper.IsECRRepo(rootFS) if err != nil { return "", "", err diff --git a/conversion_helpers_test.go b/conversion_helpers_test.go index 7b20040..3675315 100644 --- a/conversion_helpers_test.go +++ b/conversion_helpers_test.go @@ -13,6 +13,7 @@ import ( "code.cloudfoundry.org/bbs/test_helpers" fakeecrhelper "code.cloudfoundry.org/ecrhelper/fakes" "code.cloudfoundry.org/executor" + fakegcrhelper "code.cloudfoundry.org/gcrhelper/fakes" "code.cloudfoundry.org/rep" "code.cloudfoundry.org/routing-info/internalroutes" . "github.com/onsi/ginkgo/v2" @@ -283,12 +284,15 @@ var _ = Describe("Resources", func() { var ( runRequestConversionHelper rep.RunRequestConversionHelper fakeECRHelper *fakeecrhelper.FakeECRHelper + fakeGCRHelper *fakegcrhelper.FakeGCRHelper ) BeforeEach(func() { fakeECRHelper = &fakeecrhelper.FakeECRHelper{} + fakeGCRHelper = &fakegcrhelper.FakeGCRHelper{} runRequestConversionHelper = rep.RunRequestConversionHelper{ ECRHelper: fakeECRHelper, + GCRHelper: fakeGCRHelper, } }) @@ -573,6 +577,50 @@ var _ = Describe("Resources", func() { }) }) + Context("when the rootfs is a GCR/Artifact Registry repo URL and no credentials are stored", func() { + BeforeEach(func() { + desiredLRP.ImageUsername = "" + desiredLRP.ImagePassword = "" + fakeGCRHelper.IsGCRRepoReturns(true, nil) + fakeGCRHelper.GetGCRCredentialsReturns("oauth2accesstoken", "some-fresh-token", nil) + }) + + It("uses the metadata-server token", func() { + runReq, err := runRequestConversionHelper.NewRunRequestFromDesiredLRP(containerGuid, desiredLRP, &actualLRP.ActualLRPKey, &actualLRP.ActualLRPInstanceKey, stackPathMap, rep.LayeringModeSingleLayer) + Expect(err).NotTo(HaveOccurred()) + Expect(runReq.ImageUsername).To(Equal("oauth2accesstoken")) + Expect(runReq.ImagePassword).To(Equal("some-fresh-token")) + }) + + Context("when checking for GCR repo fails", func() { + BeforeEach(func() { + fakeGCRHelper.IsGCRRepoReturns(false, errors.New("disaster")) + }) + + It("returns an error", func() { + _, err := runRequestConversionHelper.NewRunRequestFromDesiredLRP(containerGuid, desiredLRP, &actualLRP.ActualLRPKey, &actualLRP.ActualLRPInstanceKey, stackPathMap, rep.LayeringModeSingleLayer) + Expect(err).To(HaveOccurred()) + }) + }) + + }) + + Context("when the rootfs is a GCR/Artifact Registry repo URL but credentials are stored", func() { + BeforeEach(func() { + desiredLRP.ImageUsername = "_json_key" + desiredLRP.ImagePassword = `{"type":"service_account"}` + }) + + It("passes through the stored credentials without checking GCR", func() { + runReq, err := runRequestConversionHelper.NewRunRequestFromDesiredLRP(containerGuid, desiredLRP, &actualLRP.ActualLRPKey, &actualLRP.ActualLRPInstanceKey, stackPathMap, rep.LayeringModeSingleLayer) + Expect(err).NotTo(HaveOccurred()) + Expect(runReq.ImageUsername).To(Equal("_json_key")) + Expect(runReq.ImagePassword).To(Equal(`{"type":"service_account"}`)) + Expect(fakeGCRHelper.IsGCRRepoCallCount()).To(Equal(0)) + Expect(fakeGCRHelper.GetGCRCredentialsCallCount()).To(Equal(0)) + }) + }) + Context("when the rootfs is ECR repo URL", func() { BeforeEach(func() { fakeECRHelper.IsECRRepoReturns(true, nil) @@ -920,6 +968,52 @@ var _ = Describe("Resources", func() { }) }) + Context("when the rootfs is a GCR/Artifact Registry repo URL and no credentials are stored", func() { + BeforeEach(func() { + task.RootFs = "docker://europe-west3-docker.pkg.dev/my-project/my-repo/my-image:latest" + task.ImageUsername = "" + task.ImagePassword = "" + fakeGCRHelper.IsGCRRepoReturns(true, nil) + fakeGCRHelper.GetGCRCredentialsReturns("oauth2accesstoken", "some-fresh-token", nil) + }) + + It("uses the metadata-server token", func() { + runReq, err := runRequestConversionHelper.NewRunRequestFromTask(task, stackPathMap, rep.LayeringModeSingleLayer) + Expect(err).NotTo(HaveOccurred()) + Expect(runReq.ImageUsername).To(Equal("oauth2accesstoken")) + Expect(runReq.ImagePassword).To(Equal("some-fresh-token")) + }) + + Context("when checking for GCR repo fails", func() { + BeforeEach(func() { + fakeGCRHelper.IsGCRRepoReturns(false, errors.New("disaster")) + }) + + It("returns an error", func() { + _, err := runRequestConversionHelper.NewRunRequestFromTask(task, stackPathMap, rep.LayeringModeSingleLayer) + Expect(err).To(HaveOccurred()) + }) + }) + + }) + + Context("when the rootfs is a GCR/Artifact Registry repo URL but credentials are stored", func() { + BeforeEach(func() { + task.RootFs = "docker://europe-west3-docker.pkg.dev/my-project/my-repo/my-image:latest" + task.ImageUsername = "_json_key" + task.ImagePassword = `{"type":"service_account"}` + }) + + It("passes through the stored credentials without checking GCR", func() { + runReq, err := runRequestConversionHelper.NewRunRequestFromTask(task, stackPathMap, rep.LayeringModeSingleLayer) + Expect(err).NotTo(HaveOccurred()) + Expect(runReq.ImageUsername).To(Equal("_json_key")) + Expect(runReq.ImagePassword).To(Equal(`{"type":"service_account"}`)) + Expect(fakeGCRHelper.IsGCRRepoCallCount()).To(Equal(0)) + Expect(fakeGCRHelper.GetGCRCredentialsCallCount()).To(Equal(0)) + }) + }) + Context("when the rootfs is ECR repo URL", func() { BeforeEach(func() { fakeECRHelper.IsECRRepoReturns(true, nil) diff --git a/generator/internal/ordinary_lrp_processor.go b/generator/internal/ordinary_lrp_processor.go index 52429e5..be156d4 100644 --- a/generator/internal/ordinary_lrp_processor.go +++ b/generator/internal/ordinary_lrp_processor.go @@ -5,6 +5,7 @@ import ( "code.cloudfoundry.org/bbs/models" "code.cloudfoundry.org/ecrhelper" "code.cloudfoundry.org/executor" + "code.cloudfoundry.org/gcrhelper" "code.cloudfoundry.org/lager/v3" "code.cloudfoundry.org/rep" ) @@ -27,7 +28,10 @@ func newOrdinaryLRPProcessor( stackPathMap rep.StackPathMap, layeringMode string, ) LRPProcessor { - runRequestConversionHelper := rep.RunRequestConversionHelper{ECRHelper: ecrhelper.NewECRHelper()} + runRequestConversionHelper := rep.RunRequestConversionHelper{ + ECRHelper: ecrhelper.NewECRHelper(), + GCRHelper: gcrhelper.NewGCRHelper(), + } return &ordinaryLRPProcessor{ bbsClient: bbsClient, diff --git a/generator/internal/ordinary_lrp_processor_test.go b/generator/internal/ordinary_lrp_processor_test.go index 5c8ae6c..f636d66 100644 --- a/generator/internal/ordinary_lrp_processor_test.go +++ b/generator/internal/ordinary_lrp_processor_test.go @@ -10,6 +10,7 @@ import ( "code.cloudfoundry.org/bbs/models/test/model_helpers" fakeecrhelper "code.cloudfoundry.org/ecrhelper/fakes" "code.cloudfoundry.org/executor" + fakegcrhelper "code.cloudfoundry.org/gcrhelper/fakes" "code.cloudfoundry.org/lager/v3/lagertest" "code.cloudfoundry.org/rep" "code.cloudfoundry.org/rep/evacuation/evacuation_context/fake_evacuation_context" @@ -139,7 +140,10 @@ var _ = Describe("OrdinaryLRPProcessor", func() { It("runs the container", func() { Expect(containerDelegate.RunContainerCallCount()).To(Equal(1)) - runRequestConversionHelper := rep.RunRequestConversionHelper{ECRHelper: &fakeecrhelper.FakeECRHelper{}} + runRequestConversionHelper := rep.RunRequestConversionHelper{ + ECRHelper: &fakeecrhelper.FakeECRHelper{}, + GCRHelper: &fakegcrhelper.FakeGCRHelper{}, + } expectedRunRequest, err := runRequestConversionHelper.NewRunRequestFromDesiredLRP(container.Guid, desiredLRP, &expectedLrpKey, &expectedInstanceKey, rep.StackPathMap{}, "") Expect(err).NotTo(HaveOccurred()) diff --git a/generator/internal/task_processor.go b/generator/internal/task_processor.go index 63369e2..1cd729e 100644 --- a/generator/internal/task_processor.go +++ b/generator/internal/task_processor.go @@ -5,6 +5,7 @@ import ( "code.cloudfoundry.org/bbs/models" "code.cloudfoundry.org/ecrhelper" "code.cloudfoundry.org/executor" + "code.cloudfoundry.org/gcrhelper" "code.cloudfoundry.org/lager/v3" "code.cloudfoundry.org/rep" ) @@ -30,7 +31,10 @@ type taskProcessor struct { } func NewTaskProcessor(bbs bbs.InternalClient, containerDelegate ContainerDelegate, cellID string, stackPathMap rep.StackPathMap, layeringMode string) TaskProcessor { - runRequestConversionHelper := rep.RunRequestConversionHelper{ECRHelper: ecrhelper.NewECRHelper()} + runRequestConversionHelper := rep.RunRequestConversionHelper{ + ECRHelper: ecrhelper.NewECRHelper(), + GCRHelper: gcrhelper.NewGCRHelper(), + } return &taskProcessor{ bbsClient: bbs, diff --git a/generator/internal/task_processor_test.go b/generator/internal/task_processor_test.go index 50e4497..4566e64 100644 --- a/generator/internal/task_processor_test.go +++ b/generator/internal/task_processor_test.go @@ -8,6 +8,7 @@ import ( "code.cloudfoundry.org/bbs/models/test/model_helpers" fakeecrhelper "code.cloudfoundry.org/ecrhelper/fakes" "code.cloudfoundry.org/executor" + fakegcrhelper "code.cloudfoundry.org/gcrhelper/fakes" "code.cloudfoundry.org/lager/v3/lagertest" "code.cloudfoundry.org/rep" "code.cloudfoundry.org/rep/generator/internal" @@ -42,7 +43,10 @@ var _ = Describe("TaskProcessor", func() { processor = internal.NewTaskProcessor(bbsClient, containerDelegate, expectedCellID, rep.StackPathMap{}, "") task = model_helpers.NewValidTask(taskGuid) - runRequestConversionHelper := rep.RunRequestConversionHelper{ECRHelper: &fakeecrhelper.FakeECRHelper{}} + runRequestConversionHelper := rep.RunRequestConversionHelper{ + ECRHelper: &fakeecrhelper.FakeECRHelper{}, + GCRHelper: &fakegcrhelper.FakeGCRHelper{}, + } expectedRunRequest, err = runRequestConversionHelper.NewRunRequestFromTask(task, rep.StackPathMap{}, "") Expect(err).NotTo(HaveOccurred())