diff --git a/api/ocm/extensions/repositories/genericocireg/annotation_test.go b/api/ocm/extensions/repositories/genericocireg/annotation_test.go new file mode 100644 index 0000000000..fa55bca87f --- /dev/null +++ b/api/ocm/extensions/repositories/genericocireg/annotation_test.go @@ -0,0 +1,86 @@ +package genericocireg_test + +import ( + . "github.com/mandelsoft/goutils/testutils" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "ocm.software/ocm/api/helper/builder" + + "ocm.software/ocm/api/oci/extensions/repositories/ctf" + metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" + resourcetypes "ocm.software/ocm/api/ocm/extensions/artifacttypes" + "ocm.software/ocm/api/utils/accessio" + "ocm.software/ocm/api/utils/accessobj" + "ocm.software/ocm/api/utils/mime" +) + +const ( + ARCH = "/tmp/ctf" + PROVIDER = "mandelsoft" + VERSION = "v1" + TEST_CONTENT1 = "this is a test" + TEST_CONTENT2 = "this is another test" +) + +var _ = Describe("Transfer handler", func() { + var env *Builder + + BeforeEach(func() { + env = NewBuilder() + + env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() { + env.Component(COMPONENT, func() { + env.Version(VERSION, func() { + env.Provider(PROVIDER) + env.Resource("test1", "", resourcetypes.PLAIN_TEXT, metav1.LocalRelation, func() { + env.BlobStringData(mime.MIME_TEXT, TEST_CONTENT1) + }) + env.Resource("test2", "", resourcetypes.PLAIN_TEXT, metav1.LocalRelation, func() { + env.BlobStringData(mime.MIME_TEXT, TEST_CONTENT1) + }) + env.Resource("test3", "", resourcetypes.PLAIN_TEXT, metav1.LocalRelation, func() { + env.BlobStringData(mime.MIME_TEXT, TEST_CONTENT2) + }) + env.Source("test4", "", resourcetypes.PLAIN_TEXT, func() { + env.BlobStringData(mime.MIME_TEXT, TEST_CONTENT2) + }) + }) + }) + }) + }) + + AfterEach(func() { + env.Cleanup() + }) + + It("check expected oci layer annotation", func() { + arch := Must(ctf.Open(env, accessobj.ACC_READONLY, ARCH, 0, env)) + defer Close(arch) + c := Must(arch.LookupNamespace("component-descriptors/" + COMPONENT)) + defer Close(c) + v := Must(c.GetArtifact(VERSION)) + defer Close(v) + Expect(v.GetDescriptor()).To(YAMLEqual(` + mediaType: application/vnd.oci.image.manifest.v1+json + schemaVersion: 2 + config: + digest: sha256:edf034a303e8cc7e5a05c522bb5fc74a09a00ed3aca390ffafba1020c97470cc + mediaType: application/vnd.ocm.software.component.config.v1+json + size: 201 + layers: + - digest: sha256:43d7113c5e6dd84c617477c5713368cffb86b059808df176bbf3e02849ea6b3e + mediaType: application/vnd.ocm.software.component-descriptor.v2+yaml+tar + size: 3584 + - annotations: + ocm-artifact: '[{"kind":"resource","identity":{"name":"test1"}},{"kind":"resource","identity":{"name":"test2"}}]' + digest: sha256:2e99758548972a8e8822ad47fa1017ff72f06f3ff6a016851f45c398732bc50c + mediaType: text/plain + size: 14 + - annotations: + ocm-artifact: '[{"kind":"resource","identity":{"name":"test3"}},{"kind":"source","identity":{"name":"test4"}}]' + digest: sha256:f69bff44070ba35d7169196ba0095425979d96346a31486b507b4a3f77bd356d + mediaType: text/plain + size: 20 +`)) + }) +}) diff --git a/api/ocm/extensions/repositories/genericocireg/componentversion.go b/api/ocm/extensions/repositories/genericocireg/componentversion.go index 18317783ea..55e6225ef5 100644 --- a/api/ocm/extensions/repositories/genericocireg/componentversion.go +++ b/api/ocm/extensions/repositories/genericocireg/componentversion.go @@ -13,6 +13,7 @@ import ( "ocm.software/ocm/api/oci/artdesc" "ocm.software/ocm/api/oci/extensions/repositories/artifactset" "ocm.software/ocm/api/ocm/compdesc" + metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" "ocm.software/ocm/api/ocm/cpi" "ocm.software/ocm/api/ocm/cpi/accspeccpi" "ocm.software/ocm/api/ocm/cpi/repocpi" @@ -27,6 +28,7 @@ import ( "ocm.software/ocm/api/utils/errkind" common "ocm.software/ocm/api/utils/misc" "ocm.software/ocm/api/utils/refmgmt" + "ocm.software/ocm/api/utils/runtime" ) // newComponentVersionAccess creates a component access for the artifact access, if this fails the artifact acess is closed. @@ -147,6 +149,20 @@ func (c *ComponentVersionContainer) SetDescriptor(cd *compdesc.ComponentDescript return c.Update() } +type LayerAnnotations []ArtifactInfo + +type ArtifactInfo struct { + // Kind specifies whether the artifact is a source, resource or a label + Kind string `json:"kind"` + Identity metav1.Identity `json:"identity"` +} + +const ( + ARTKIND_RESOURCE = "resource" + ARTKIND_SOURCE = "source" + OCM_ARTIFACT = "ocm-artifact" +) + func (c *ComponentVersionContainer) Update() error { logger := Logger(c.GetContext()).WithValues("cv", common.NewNameVersion(c.comp.name, c.version)) err := c.Check() @@ -155,6 +171,8 @@ func (c *ComponentVersionContainer) Update() error { } if c.state.HasChanged() { + layerAnnotations := map[int]LayerAnnotations{} + logger.Debug("update component version") desc := c.GetDescriptor() layers := set.Set[int]{} @@ -167,6 +185,10 @@ func (c *ComponentVersionContainer) Update() error { return fmt.Errorf("failed resource layer evaluation: %w", err) } if l > 0 { + layerAnnotations[l] = append(layerAnnotations[l], ArtifactInfo{ + Kind: ARTKIND_RESOURCE, + Identity: r.GetIdentity(desc.Resources), + }) layers.Delete(l) } if s != r.Access { @@ -179,6 +201,10 @@ func (c *ComponentVersionContainer) Update() error { return fmt.Errorf("failed source layer evaluation: %w", err) } if l > 0 { + layerAnnotations[l] = append(layerAnnotations[l], ArtifactInfo{ + Kind: ARTKIND_SOURCE, + Identity: r.GetIdentity(desc.Sources), + }) layers.Delete(l) } if s != r.Access { @@ -186,6 +212,17 @@ func (c *ComponentVersionContainer) Update() error { } } m := c.manifest.GetDescriptor() + + for layer, info := range layerAnnotations { + data, err := runtime.DefaultJSONEncoding.Marshal(info) + if err != nil { + return err + } + if m.Layers[layer].Annotations == nil { + m.Layers[layer].Annotations = map[string]string{} + } + m.Layers[layer].Annotations[OCM_ARTIFACT] = string(data) + } i := len(m.Layers) - 1 for i > 0 { diff --git a/api/ocm/resolver_test.go b/api/ocm/resolver_test.go index ca4f7bd3d4..321bd952b3 100644 --- a/api/ocm/resolver_test.go +++ b/api/ocm/resolver_test.go @@ -8,11 +8,11 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "ocm.software/ocm/api/helper/builder" - "ocm.software/ocm/api/ocm/internal" "ocm.software/ocm/api/ocm" "ocm.software/ocm/api/ocm/extensions/repositories/ctf" "ocm.software/ocm/api/ocm/extensions/repositories/ocireg" + "ocm.software/ocm/api/ocm/internal" "ocm.software/ocm/api/utils/accessio" "ocm.software/ocm/api/utils/accessobj" ) diff --git a/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/typehandler_test.go b/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/typehandler_test.go index 1000de89ed..3d1e5b8367 100644 --- a/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/typehandler_test.go +++ b/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/typehandler_test.go @@ -15,13 +15,14 @@ import ( "ocm.software/ocm/api/utils/accessobj" ) -const ARCH = "ctf" -const COMP = "acme.org/comp1" -const VERS1 = "1.0.0" -const VERS2 = "2.0.0" +const ( + ARCH = "ctf" + COMP = "acme.org/comp1" + VERS1 = "1.0.0" + VERS2 = "2.0.0" +) var _ = Describe("version handler", func() { - var env *TestEnv BeforeEach(func() { diff --git a/cmds/ocm/commands/ocmcmds/common/inputs/types/npm/input_test.go b/cmds/ocm/commands/ocmcmds/common/inputs/types/npm/input_test.go index f7c1600096..5be41f82c9 100644 --- a/cmds/ocm/commands/ocmcmds/common/inputs/types/npm/input_test.go +++ b/cmds/ocm/commands/ocmcmds/common/inputs/types/npm/input_test.go @@ -3,10 +3,10 @@ package npm_test import ( . "github.com/onsi/ginkgo/v2" . "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/inputs/testutils" - "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/inputs/types/npm" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/inputs" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/inputs/options" + "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/inputs/types/npm" ) var _ = Describe("Input Type", func() {