From aee8bb471a4bc6287bb34a8835082814e170c33e Mon Sep 17 00:00:00 2001 From: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> Date: Mon, 12 May 2025 19:31:40 +0200 Subject: [PATCH 1/2] fix: add extra identity to the resource lookup reference Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> On-behalf-of: @SAP gergely.brautigam@sap.com --- pkg/fakes/ocm.go | 17 +++++-- pkg/ocm/credentials.go | 7 +-- pkg/ocm/ocm.go | 8 ++- pkg/ocm/ocm_test.go | 112 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 8 deletions(-) diff --git a/pkg/fakes/ocm.go b/pkg/fakes/ocm.go index 83b8fc7a..0686d4e3 100644 --- a/pkg/fakes/ocm.go +++ b/pkg/fakes/ocm.go @@ -51,6 +51,7 @@ type Resource[M any] struct { // AccessOptions to modify the access of the resource. AccessOptions []AccessOptionFunc + ExtraIdentity ocmmetav1.Identity } // Sign defines the two needed values to perform a component signing. @@ -389,8 +390,15 @@ func (c *Component) GetResources() []ocm.ResourceAccess { func (c *Component) GetResource(meta ocmmetav1.Identity) (ocm.ResourceAccess, error) { for _, r := range c.Resources { - // && r.Version == meta["version"] --> add this at some point if r.Name == meta["name"] { + if r.ExtraIdentity != nil { + if r.ExtraIdentity.Equals(meta.ExtraIdentity()) { + return r, nil + } + + continue + } + return r, nil } } @@ -413,9 +421,10 @@ var _ ocm.ResourceAccess = &Resource[*ocm.ResourceMeta]{} func (r *Resource[M]) Meta() *ocm.ResourceMeta { return &ocm.ResourceMeta{ ElementMeta: compdesc.ElementMeta{ - Name: r.Name, - Version: r.Version, - Labels: r.Labels, + Name: r.Name, + Version: r.Version, + Labels: r.Labels, + ExtraIdentity: r.ExtraIdentity, }, Type: r.Type, Relation: r.Relation, diff --git a/pkg/ocm/credentials.go b/pkg/ocm/credentials.go index 60e60296..dbca3d44 100644 --- a/pkg/ocm/credentials.go +++ b/pkg/ocm/credentials.go @@ -5,16 +5,17 @@ import ( "fmt" "net/url" - "github.com/open-component-model/ocm-controller/api/v1alpha1" corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "ocm.software/ocm/api/credentials" credconfig "ocm.software/ocm/api/credentials/config" "ocm.software/ocm/api/credentials/extensions/repositories/dockerconfig" "ocm.software/ocm/api/ocm" common "ocm.software/ocm/api/utils/misc" - "ocm.software/ocm/api/utils/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/open-component-model/ocm-controller/api/v1alpha1" ) // ConfigureCredentials takes a repository url and secret ref and configures access to an OCI repository. diff --git a/pkg/ocm/ocm.go b/pkg/ocm/ocm.go index f98afac8..bc36a125 100644 --- a/pkg/ocm/ocm.go +++ b/pkg/ocm/ocm.go @@ -235,9 +235,15 @@ func (c *Client) GetResource( var identities []ocmmetav1.Identity identities = append(identities, resource.ReferencePath...) + var extras []string + for k, v := range resource.ExtraIdentity { + extras = append(extras, k, v) + } + + // NewIdentity creates name based identity, and extra identity is added as a key value pair. res, _, err := resourcerefs.ResolveResourceReference( cva, - ocmmetav1.NewNestedResourceRef(ocmmetav1.NewIdentity(resource.Name), identities), + ocmmetav1.NewNestedResourceRef(ocmmetav1.NewIdentity(resource.Name, extras...), identities), cva.Repository(), ) if err != nil { diff --git a/pkg/ocm/ocm_test.go b/pkg/ocm/ocm_test.go index 460f76f6..3b964062 100644 --- a/pkg/ocm/ocm_test.go +++ b/pkg/ocm/ocm_test.go @@ -1036,3 +1036,115 @@ func TestClient_VerifyComponentDifferentPublicKey(t *testing.T) { require.Error(t, err) assert.False(t, verified, "verified should have been false, but it did not") } + +func TestResourceLookupWithVersionAndExtraIdentity(t *testing.T) { + // Create Two resources, identical in name but differs in extraIdentity. + // It should find the right resource. + component := "ocm.software/ocm-demo-index" + resource := "remote-controller-demo" + resourceVersion := "v0.0.1" + data1 := "testdata1" + data2 := "testdata2" + + octx := fakeocm.NewFakeOCMContext() + + comp := &fakeocm.Component{ + Name: component, + Version: "v0.0.1", + } + res1 := &fakeocm.Resource[*ocm.ResourceMeta]{ + ExtraIdentity: map[string]string{ + "type": "chart", + }, + Name: resource, + Version: resourceVersion, + Data: []byte(data1), + Component: comp, + Kind: "localBlob", + Type: "ociBlob", + } + res2 := &fakeocm.Resource[*ocm.ResourceMeta]{ + ExtraIdentity: map[string]string{ + "type": "config", + }, + Name: resource, + Version: resourceVersion, + Data: []byte(data2), + Component: comp, + Kind: "localBlob", + Type: "ociBlob", + } + comp.Resources = append(comp.Resources, res1, res2) + + _ = octx.AddComponent(comp) + + cd := &v1alpha1.ComponentDescriptor{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "github.com-open-component-model-ocm-demo-index-v0.0.1-12345", + }, + Spec: v1alpha1.ComponentDescriptorSpec{ + Version: "v0.0.1", + }, + } + + fakeKubeClient := env.FakeKubeClient(WithObjects(cd)) + cache := &fakes.FakeCache{} + cache.IsCachedReturns(false, nil) + cache.FetchDataByDigestReturns(io.NopCloser(strings.NewReader("mockdata")), nil) + cache.PushDataReturns("sha256:8fa155245ea8d3f2ea3add7d090d42dfb0e22799018fded6aae24f0c1a1c3f38", nil) + + ocmClient := NewClient(fakeKubeClient, cache) + + cv := &v1alpha1.ComponentVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "default", + }, + Spec: v1alpha1.ComponentVersionSpec{ + Component: component, + Version: v1alpha1.Version{ + Semver: "v0.0.1", + }, + Repository: v1alpha1.Repository{ + URL: "localhost", + }, + }, + Status: v1alpha1.ComponentVersionStatus{ + ReconciledVersion: "v0.0.1", + ComponentDescriptor: v1alpha1.Reference{ + Name: component, + Version: "v0.0.1", + ComponentDescriptorRef: meta.NamespacedObjectReference{ + Name: "github.com-open-component-model-ocm-demo-index-v0.0.1-12345", + Namespace: "default", + }, + }, + }, + } + + resourceRef := &v1alpha1.ResourceReference{ + ElementMeta: v1alpha1.ElementMeta{ + Name: "remote-controller-demo", + Version: "v0.0.1", + ExtraIdentity: map[string]string{ + "type": "config", + }, + }, + } + + reader, digest, _, err := ocmClient.GetResource(context.Background(), octx, cv, resourceRef) + require.NoError(t, err) + content, err := io.ReadAll(reader) + require.NoError(t, err) + require.Equal(t, "mockdata", string(content)) + require.Equal(t, "sha256:8fa155245ea8d3f2ea3add7d090d42dfb0e22799018fded6aae24f0c1a1c3f38", digest) + + // verify that the cache has been called with the right resource data to cache. + args := cache.PushDataCallingArgumentsOnCall(0) + + require.Equal(t, data2, args.Content) + + require.Equal(t, "sha-17579917197306559277", args.Name, "pushed name did not match constructed name from identity of the resource") + require.Equal(t, resourceRef.Version, args.Version) +} From 1eb9c0a1fd6c5dc9d646f42b47f416b1aa5ac290 Mon Sep 17 00:00:00 2001 From: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> Date: Tue, 13 May 2025 10:59:28 +0200 Subject: [PATCH 2/2] add e2e test to make sure that similar resources can be found Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> --- e2e/main_test.go | 1 + e2e/same_resource_test.go | 91 ++++++++++++++++++ e2e/suite_test.go | 4 - .../component_version.yaml | 12 +++ .../config.yaml | 36 +++++++ .../manifests.tar | Bin 0 -> 1367 bytes .../resource1.yaml | 15 +++ .../resource2.yaml | 15 +++ go.mod | 11 ++- go.sum | 24 ++--- 10 files changed, 188 insertions(+), 21 deletions(-) create mode 100644 e2e/same_resource_test.go create mode 100644 e2e/testdata/testOCMControllerMultipleSameResources/component_version.yaml create mode 100644 e2e/testdata/testOCMControllerMultipleSameResources/config.yaml create mode 100644 e2e/testdata/testOCMControllerMultipleSameResources/manifests.tar create mode 100644 e2e/testdata/testOCMControllerMultipleSameResources/resource1.yaml create mode 100644 e2e/testdata/testOCMControllerMultipleSameResources/resource2.yaml diff --git a/e2e/main_test.go b/e2e/main_test.go index e18e64b9..d6c7108b 100644 --- a/e2e/main_test.go +++ b/e2e/main_test.go @@ -39,6 +39,7 @@ var ( testRepoName = "ocm-controller-test" testRepoSignedName = "ocm-controller-signed-test" testRepoHelmName = "ocm-controller-helm-test" + testRepoSameName = "ocm-controller-same-test" testHelmChartBasedResource = "testHelmChartResource" testOCMControllerPath = "testOCMController" testSignedComponentsPath = "testSignedOCIRegistryComponents" diff --git a/e2e/same_resource_test.go b/e2e/same_resource_test.go new file mode 100644 index 00000000..9438fef4 --- /dev/null +++ b/e2e/same_resource_test.go @@ -0,0 +1,91 @@ +//go:build e2e + +package e2e + +import ( + "os" + "path/filepath" + "testing" + + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + "github.com/open-component-model/ocm-controller/api/v1alpha1" + "github.com/open-component-model/ocm-e2e-framework/shared" + "sigs.k8s.io/e2e-framework/pkg/features" + + "github.com/open-component-model/ocm-e2e-framework/shared/steps/setup" +) + +func TestSameResource(t *testing.T) { + management := features.New("Configure Management Repository"). + Setup(setup.AddScheme(v1alpha1.AddToScheme)). + Setup(setup.AddScheme(sourcev1.AddToScheme)). + Setup(setup.AddScheme(kustomizev1.AddToScheme)). + Setup(setup.AddGitRepository(testRepoSameName)). + Setup(setup.AddFluxSyncForRepo(testRepoSameName, destinationPrefix, ocmNamespace)) + + configContent, err := os.ReadFile(filepath.Join("testdata", "testOCMControllerMultipleSameResources", "config.yaml")) + if err != nil { + t.Fatal("failed to read config file: %w", err) + } + + manifestContent, err := os.ReadFile(filepath.Join("testdata", "testOCMControllerMultipleSameResources", "manifests.tar")) + if err != nil { + t.Fatal("failed to read config file: %w", err) + } + + component := setup.Component{ + Component: shared.Component{ + Name: "component.name.resources/same", + Version: "v1.0.0", + }, + ComponentVersionModifications: []shared.ComponentModification{ + shared.BlobResource(shared.Resource{ + Name: "same", + Data: string(configContent), + Type: "configdata.ocm.software", + Version: "1.0.0", + ExtraIdentity: map[string]string{ + "type": "config", + }, + }), + shared.BlobResource(shared.Resource{ + Name: "same", + Data: string(manifestContent), + Type: "kustomize.ocm.fluxcd.io", + Version: "1.0.0", + ExtraIdentity: map[string]string{ + "type": "manifest", + }, + }), + }, + } + + gitRepositoryName := "ocm-controller-test" + testName := "testOCMControllerMultipleSameResources" + + setupComponentFeature := features.New("Setup Component").Setup(setup.AddComponentVersions(component)) + componentVersionFeature := features.New("Create Manifests"). + Setup(setup.AddFilesToGitRepository(setup.File{ + RepoName: gitRepositoryName, + SourceFilepath: filepath.Join(testName, "component_version.yaml"), + DestFilepath: destinationPrefix + testName + "component_version.yaml", + }, setup.File{ + RepoName: gitRepositoryName, + SourceFilepath: filepath.Join(testName, "resource1.yaml"), + DestFilepath: destinationPrefix + testName + "resource1.yaml", + }, setup.File{ + RepoName: gitRepositoryName, + SourceFilepath: filepath.Join(testName, "resource2.yaml"), + DestFilepath: destinationPrefix + testName + "resource2.yaml", + })).Assess("check that component version component_version.yaml is ready and valid", checkIsComponentVersionReady("same-resource-component", ocmNamespace)) + + resourceAssertFeatures := features.New("Validate Resources").Setup(checkIsResourceReady("resource-1")).Setup(checkIsResourceReady("resource-2")) + + testEnv.Test(t, + setupComponentFeature.Feature(), + management.Feature(), + componentVersionFeature.Feature(), + resourceAssertFeatures.Feature(), + ) +} diff --git a/e2e/suite_test.go b/e2e/suite_test.go index 0243127c..dd258da8 100644 --- a/e2e/suite_test.go +++ b/e2e/suite_test.go @@ -16,7 +16,6 @@ import ( var ( testEnv env.Environment - kindClusterName string ocmNamespace string registryPort = 5000 gitRepositoryPort = 3000 @@ -32,14 +31,12 @@ func TestMain(m *testing.M) { path := conf.ResolveKubeConfigFile() cfg := envconf.NewWithKubeConfig(path) testEnv = env.NewWithConfig(cfg) - kindClusterName = envconf.RandomName("ocm-ctrl-e2e", 32) ocmNamespace = "ocm-system" stopChannelRegistry := make(chan struct{}, 1) stopChannelGitea := make(chan struct{}, 1) testEnv.Setup( - //envfuncs.CreateKindCluster(kindClusterName), envfuncs.CreateNamespace(ocmNamespace), shared.StartGitServer(ocmNamespace), shared.InstallFlux("latest"), @@ -53,7 +50,6 @@ func TestMain(m *testing.M) { shared.ShutdownPortForward(stopChannelRegistry), shared.ShutdownPortForward(stopChannelGitea), envfuncs.DeleteNamespace(ocmNamespace), - //envfuncs.DestroyKindCluster(kindClusterName), ) os.Exit(testEnv.Run(m)) diff --git a/e2e/testdata/testOCMControllerMultipleSameResources/component_version.yaml b/e2e/testdata/testOCMControllerMultipleSameResources/component_version.yaml new file mode 100644 index 00000000..a8eb05ef --- /dev/null +++ b/e2e/testdata/testOCMControllerMultipleSameResources/component_version.yaml @@ -0,0 +1,12 @@ +apiVersion: delivery.ocm.software/v1alpha1 +kind: ComponentVersion +metadata: + name: same-resource-component + namespace: ocm-system +spec: + component: component.name.resources/same + interval: 5s + repository: + url: registry.ocm-system.svc.cluster.local:5000 + version: + semver: ">=v1.0.0" diff --git a/e2e/testdata/testOCMControllerMultipleSameResources/config.yaml b/e2e/testdata/testOCMControllerMultipleSameResources/config.yaml new file mode 100644 index 00000000..1e129445 --- /dev/null +++ b/e2e/testdata/testOCMControllerMultipleSameResources/config.yaml @@ -0,0 +1,36 @@ +apiVersion: config.ocm.software/v1alpha1 +kind: ConfigData +metadata: + name: ocm-config-pipeline-backend + labels: + env: test +configuration: + defaults: + replicas: 1 + cacheAddr: tcp://redis:6379 + message: Hello, world! + schema: + type: object + additionalProperties: false + properties: + replicas: + type: integer + cacheAddr: + type: string + message: + type: string + rules: + - value: (( replicas )) + file: manifests/deploy.yaml + path: spec.replicas + - value: (( cacheAddr )) + file: manifests/configmap.yaml + path: data.PODINFO_CACHE_SERVER + - value: (( message )) + file: manifests/configmap.yaml + path: data.PODINFO_UI_MESSAGE +localization: + - resource: + name: image + file: manifests/deploy.yaml + image: spec.template.spec.containers[0].image diff --git a/e2e/testdata/testOCMControllerMultipleSameResources/manifests.tar b/e2e/testdata/testOCMControllerMultipleSameResources/manifests.tar new file mode 100644 index 0000000000000000000000000000000000000000..d4d9d4aed33da05dd1959b6ec5e3b53cbc448f15 GIT binary patch literal 1367 zcmV-d1*rNTiwFQthLB_c1MOMOZsRr(b_*0m-9vk7fu4x$v9KahKeV;T!JA|oqshjN zlSQ^b5ik;M6QO=8(nh?8p85bi_Si=#(3jX#AET#U`UV~OSJpa-gV@fts}B}r4~N5< zA%`4}0~+!+lS*!v)&^bIiEX3d+ZnxeY>nPyAj7gOQ^$s5TSzxd16w6zuTP~JdQ#B@ zRPl9!L4_OnfUVuWMb6lc>H9x|U^@TW#TED>3ixZPcob>_8i>`50se3->*o2#PJaH0 z0W*R0)eL_--t+k{ee}i0r4LJ`BkG~!7CJ{`q_ol}@L+g;f+zj``*I@dr>7_5uW66p z;Q2hq^1+P$l@|pXjbp(yL8a@2Vlv-oe)>jOr8 zmTa$jAGkCAO=mv-u}*YcLf5M?@pioD@o(xVP&{BehEsKFx=jeybW9u*W5+H#HFVf` zRzKN2XuRCluBlRqc4N5iNaO48zOSd)Yn-3fo5Qd5vRy+h5ODbFP67E~FF&qt-UrO$ ze_f~l-SKbOICuU#1Utp~zX{NozhsGoDR@2Vli}L?f?*q%`|Figqq=l{>1z3#m_zjywh5B4HwSUYC%zpm5&&iFSC)6Ad$rh$v|e-p^& z{}7ZClKpX>zc*YD0Si?*fb<_?l)7bvLK-j^wUa1REcDAVW?o7Tcz6P*$DqaF65vZ0 znLtcfpQoY^I9wT$!66U0a*+)!aT0al>LB-^kKiGjc5`%Sl`4T9p)*JYgOo@BOXn<3 zw}}x6#-rC~A?;Hx=%oOK^dVghV)%ZN?U0INf_b38sBb`(*FB_{Ovs5aFg#-th+#o2 zrh{dzA99Cbq=vVjseqwDz}IEH;f+ap2~9QGQb~_(-M|z_33y|xMrvfjBIeY3TQRU@ z?C%udGDX38$+Sl$KRpvcJfIz*ce-9O)K9TC4M82BhM z;G#zRMWmWAY3YiXS_C#^^qq{~RVtnmGm18cCfBO9YNi#`P>~l27oF}l7mBKY*Ani@ zTSS5rmloMcV(%7FfICIO83sG2pS4_@I5I=4R8j}+%o#kPPK?@_(>-k!tk1;GTcSMb zby-ESq|cI_g!x>$j!9;^vatUg7FbrN(S`ho#wV=pW{k>*ab?6fbUJLqe69GXP9`%6{lj42|C+w z>TuX4$k7Gh-L&mMe2+#XT1pa7YDnx4JQwuKyT1Hi((le+{Sj|93NZ$Ll}8{ye%8 z{{7~kPakAwfrVI9|5^1uuyp-r8vlgg;{V@`V7~rS!%nTH878rfnq!lD)_;OVYx4iE z95nY2?_K}N2YZo1tR1uXU)SlsMEu(%7ymY~t>XOO1hVy?Y3XNoa&5e&@-w?KW{Vc{ z1&c|~=J8(R#q;Bfv&O~l@!|1_i?*JamQ9GaHQ#!)-)hyr*@yPiE|&;C6e(DpaIuh* ZcG%WqyQ@Hf0tNmz_!si3xnTe>003#