From bb48058f12d6ec613eceb68d34f6da616bf4958b Mon Sep 17 00:00:00 2001 From: Ryan Cole Date: Mon, 17 Jul 2023 09:37:34 -0400 Subject: [PATCH] fix(stoneintg-505): use snapshot components when creating SEB The integration service added a list of components to the SnapshotEnvironmentBinding upon creation. Prior to this change the list was derived from the Application associated with the snapshot. This changes makes the integration service derive the components from the snapshot itself. Signed-off-by: Ryan Cole --- controllers/snapshot/snapshot_adapter.go | 2 +- controllers/snapshot/snapshot_adapter_test.go | 2 +- loader/loader.go | 22 ++++++++++ loader/loader_mock.go | 10 +++++ loader/loader_mock_test.go | 15 +++++++ loader/loader_test.go | 44 +++++++++++++++++++ 6 files changed, 93 insertions(+), 2 deletions(-) diff --git a/controllers/snapshot/snapshot_adapter.go b/controllers/snapshot/snapshot_adapter.go index 04f0e7a17..24655e672 100644 --- a/controllers/snapshot/snapshot_adapter.go +++ b/controllers/snapshot/snapshot_adapter.go @@ -344,7 +344,7 @@ func (a *Adapter) EnsureSnapshotEnvironmentBindingExist() (reconciler.OperationR return reconciler.RequeueWithError(err) } - components, err := a.loader.GetAllApplicationComponents(a.client, a.context, a.application) + components, err := a.loader.GetAllSnapshotComponents(a.client, a.context, a.snapshot) if err != nil { return reconciler.RequeueWithError(err) } diff --git a/controllers/snapshot/snapshot_adapter_test.go b/controllers/snapshot/snapshot_adapter_test.go index 5e8abfa39..bac4bce98 100644 --- a/controllers/snapshot/snapshot_adapter_test.go +++ b/controllers/snapshot/snapshot_adapter_test.go @@ -362,7 +362,7 @@ var _ = Describe("Snapshot Adapter", Ordered, func() { Resource: env, }, { - ContextKey: loader.ApplicationComponentsContextKey, + ContextKey: loader.SnapshotComponentsContextKey, Resource: []applicationapiv1alpha1.Component{*hasComp}, }, { diff --git a/loader/loader.go b/loader/loader.go index cf5b747f8..60480d52d 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -38,6 +38,7 @@ type ObjectLoader interface { GetAllEnvironments(c client.Client, ctx context.Context, application *applicationapiv1alpha1.Application) (*[]applicationapiv1alpha1.Environment, error) GetReleasesWithSnapshot(c client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot) (*[]releasev1alpha1.Release, error) GetAllApplicationComponents(c client.Client, ctx context.Context, application *applicationapiv1alpha1.Application) (*[]applicationapiv1alpha1.Component, error) + GetAllSnapshotComponents(c client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot) (*[]applicationapiv1alpha1.Component, error) GetApplicationFromSnapshot(c client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot) (*applicationapiv1alpha1.Application, error) GetComponentFromSnapshot(c client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot) (*applicationapiv1alpha1.Component, error) GetComponentFromPipelineRun(c client.Client, ctx context.Context, pipelineRun *tektonv1beta1.PipelineRun) (*applicationapiv1alpha1.Component, error) @@ -119,6 +120,27 @@ func (l *loader) GetAllApplicationComponents(c client.Client, ctx context.Contex return &applicationComponents.Items, nil } +// GetAllSnapshotComponents loads from the cluster all Components associated with the given Snapshot. +// If the Snapshot doesn't have any Components or this is not found in the cluster, an error will be returned. +func (l *loader) GetAllSnapshotComponents(c client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot) (*[]applicationapiv1alpha1.Component, error) { + components := []applicationapiv1alpha1.Component{} + + for _, sc := range snapshot.Spec.Components { + component := &applicationapiv1alpha1.Component{} + err := c.Get(ctx, types.NamespacedName{ + Namespace: snapshot.Namespace, + Name: sc.Name, + }, component) + if err != nil { + return nil, err + } + + components = append(components, *component) + } + + return &components, nil +} + // GetApplicationFromSnapshot loads from the cluster the Application referenced in the given Snapshot. // If the Snapshot doesn't specify an Component or this is not found in the cluster, an error will be returned. func (l *loader) GetApplicationFromSnapshot(c client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot) (*applicationapiv1alpha1.Application, error) { diff --git a/loader/loader_mock.go b/loader/loader_mock.go index f0ffe4beb..f683a6bf8 100644 --- a/loader/loader_mock.go +++ b/loader/loader_mock.go @@ -48,6 +48,7 @@ const ( IntegrationTestScenarioContextKey contextKey = iota TaskRunContextKey contextKey = iota ApplicationComponentsContextKey contextKey = iota + SnapshotComponentsContextKey contextKey = iota EnvironmentContextKey contextKey = iota ReleaseContextKey contextKey = iota PipelineRunsContextKey contextKey = iota @@ -122,6 +123,15 @@ func (l *mockLoader) GetAllApplicationComponents(c client.Client, ctx context.Co return &components, err } +// GetAllSnapshotComponents returns the resource and error passed as values of the context. +func (l *mockLoader) GetAllSnapshotComponents(c client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot) (*[]applicationapiv1alpha1.Component, error) { + if ctx.Value(SnapshotComponentsContextKey) == nil { + return l.loader.GetAllSnapshotComponents(c, ctx, snapshot) + } + components, err := getMockedResourceAndErrorFromContext(ctx, SnapshotComponentsContextKey, []applicationapiv1alpha1.Component{}) + return &components, err +} + // GetApplicationFromSnapshot returns the resource and error passed as values of the context. func (l *mockLoader) GetApplicationFromSnapshot(c client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot) (*applicationapiv1alpha1.Application, error) { if ctx.Value(ApplicationContextKey) == nil { diff --git a/loader/loader_mock_test.go b/loader/loader_mock_test.go index f0f7dce32..5f3c04ecf 100644 --- a/loader/loader_mock_test.go +++ b/loader/loader_mock_test.go @@ -139,6 +139,21 @@ var _ = Describe("Release Adapter", Ordered, func() { }) }) + Context("When calling GetAllSnapshotComponents", func() { + It("returns resource and error from the context", func() { + snapshotComponents := []applicationapiv1alpha1.Component{} + mockContext := GetMockedContext(ctx, []MockData{ + { + ContextKey: SnapshotComponentsContextKey, + Resource: snapshotComponents, + }, + }) + resource, err := loader.GetAllSnapshotComponents(nil, mockContext, nil) + Expect(resource).To(Equal(&snapshotComponents)) + Expect(err).To(BeNil()) + }) + }) + Context("When calling GetApplicationFromSnapshot", func() { It("returns resource and error from the context", func() { application := &applicationapiv1alpha1.Application{} diff --git a/loader/loader_test.go b/loader/loader_test.go index 66d0dccf7..9c2e8740b 100644 --- a/loader/loader_test.go +++ b/loader/loader_test.go @@ -410,6 +410,50 @@ var _ = Describe("Loader", Ordered, func() { Expect(applicationComponents).NotTo(BeNil()) }) + It("ensures the Snapshot Components can be found ", func() { + snapshotComponents, err := loader.GetAllSnapshotComponents(k8sClient, ctx, hasSnapshot) + Expect(err).To(BeNil()) + Expect(snapshotComponents).NotTo(BeNil()) + }) + + It("ensures GetAllSnapshotComponents does not gather non-snapshot application components ", func() { + // otherComp has the same namespace and application as the snapshot, + // but does not belong to the snapshot itself. When creating SEBs + // for older snapshots we do not want to accidentally add components + // for newer snapshots. + otherComp := &applicationapiv1alpha1.Component{ + ObjectMeta: metav1.ObjectMeta{ + Name: "other-component", + Namespace: "default", + }, + Spec: applicationapiv1alpha1.ComponentSpec{ + ComponentName: "other-component", + Application: applicationName, + ContainerImage: "", + Source: applicationapiv1alpha1.ComponentSource{ + ComponentSourceUnion: applicationapiv1alpha1.ComponentSourceUnion{ + GitSource: &applicationapiv1alpha1.GitSource{ + URL: SampleRepoLink, + }, + }, + }, + }, + Status: applicationapiv1alpha1.ComponentStatus{ + LastBuiltCommit: "", + }, + } + Expect(k8sClient.Create(ctx, otherComp)).Should(Succeed()) + defer k8sClient.Delete(ctx, otherComp) + + snapshotComponents, err := loader.GetAllSnapshotComponents(k8sClient, ctx, hasSnapshot) + Expect(err).To(BeNil()) + Expect(snapshotComponents).NotTo(BeNil()) + Expect(*snapshotComponents).To(HaveLen(1)) + for _, comp := range *snapshotComponents { + Expect(comp.Name).NotTo(Equal("other-component")) + } + }) + It("ensures we can get an Application from a Snapshot ", func() { app, err := loader.GetApplicationFromSnapshot(k8sClient, ctx, hasSnapshot) Expect(err).To(BeNil())