Skip to content

Commit

Permalink
Resource resolution on CD set (#865)
Browse files Browse the repository at this point in the history
#### What this PR does / why we need it:

Introduction resolution of relative resource references of the level of
component descriptors.

So far, this the resolution was only possible on the level of the
complete component version access abstraction.
This PR adds such a functionality on the level of plain component
descriptors.
Therefore, it provides a `ComponentVersionResolver` abstraction for
component descriptors, with two
implementations: a set of component descriptors and a compound resolver
similar to the one for component version accesses.

To align the element names in package `compdesc`, the
`ComponentReference`ans been renamed to `Reference` (like `Resource` and
`Source`). The old type has been deprecated.

This functionality is required for the OCM controllers working an deep
resources for a component version.

To verify the digest of the retrieved content of a resource, a new
function
`signing.VerifyResourceDigest(cv, index, content)`
is provided. it uses the digesting type described by the component
version to recalculate the digest of the retrieved resource and verify
it against the digest described by the component version.
  • Loading branch information
mandelsoft authored Sep 3, 2024
1 parent 484ce45 commit 74e50a9
Show file tree
Hide file tree
Showing 69 changed files with 1,998 additions and 137 deletions.
49 changes: 49 additions & 0 deletions api/helper/builder/oci_artifactset.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
package builder

import (
"fmt"
"slices"

"github.com/mandelsoft/vfs/pkg/vfs"

"ocm.software/ocm/api/oci"
"ocm.software/ocm/api/oci/cpi"
"ocm.software/ocm/api/oci/extensions/repositories/artifactset"
"ocm.software/ocm/api/utils/accessio"
"ocm.software/ocm/api/utils/accessobj"
"ocm.software/ocm/api/utils/blobaccess"
"ocm.software/ocm/api/utils/blobaccess/file"
)

const T_OCIARTIFACTSET = "artifact set"
Expand All @@ -18,3 +27,43 @@ func (b *Builder) ArtifactSet(path string, fmt accessio.FileFormat, f ...func())
r.Annotate(name, value)
}}, f)
}

func (b *Builder) ArtifactSetBlob(main string, f ...func()) {
b.expect(b.blob, T_BLOBACCESS)
arch, err := vfs.TempFile(b.FileSystem(), "", "artifact-*.tgz")
b.failOn(err)
b.FileSystem().Remove(arch.Name())

r, err := artifactset.Open(accessobj.ACC_WRITABLE|accessobj.ACC_CREATE, arch.Name(), 0o777, accessio.FormatTGZ, accessio.PathFileSystem(b.FileSystem()))
b.failOn(err)

b.configure(&ociNamespace{NamespaceAccess: &artifactSink{b, arch.Name(), main, r, ""}, kind: T_OCIARTIFACTSET, annofunc: func(name, value string) {
r.Annotate(name, value)
}}, append(f, func() {
b.Annotation(artifactset.MAINARTIFACT_ANNOTATION, main)
}))
}

type artifactSink struct {
builder *Builder
arch string
main string
oci.NamespaceAccess
mime string
}

func (s *artifactSink) AddArtifact(art cpi.Artifact, tags ...string) (blobaccess.BlobAccess, error) {
if slices.Contains(tags, s.main) {
s.mime = art.Artifact().MimeType()
}
return s.NamespaceAccess.AddArtifact(art, tags...)
}

func (s *artifactSink) Close() error {
if s.mime == "" {
s.NamespaceAccess.Close()
return fmt.Errorf("main artifact not defined")
}
*s.builder.blob = blobaccess.ForTemporaryFilePath(artifactset.MediaType(s.mime), s.arch, file.WithFileSystem(s.builder.FileSystem()))
return s.NamespaceAccess.Close()
}
2 changes: 1 addition & 1 deletion api/helper/builder/ocm_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
type ocmReference struct {
base

meta compdesc.ComponentReference
meta compdesc.Reference
}

const T_OCMREF = "reference"
Expand Down
1 change: 1 addition & 0 deletions api/oci/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type (
IntermediateRepositorySpecAspect = internal.IntermediateRepositorySpecAspect
GenericRepositorySpec = internal.GenericRepositorySpec
ArtifactAccess = internal.ArtifactAccess
Artifact = internal.Artifact
NamespaceLister = internal.NamespaceLister
NamespaceAccess = internal.NamespaceAccess
ManifestAccess = internal.ManifestAccess
Expand Down
44 changes: 27 additions & 17 deletions api/ocm/compdesc/componentdescriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"ocm.software/ocm/api/ocm/compdesc/equivalent"
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
"ocm.software/ocm/api/ocm/selectors/accessors"
"ocm.software/ocm/api/utils/errkind"
"ocm.software/ocm/api/utils/runtime"
"ocm.software/ocm/api/utils/semverutils"
)
Expand All @@ -18,7 +19,13 @@ const InternalSchemaVersion = "internal"

var NotFound = errors.ErrNotFound()

const KIND_REFERENCE = "component reference"
const (
KIND_COMPONENT = errkind.KIND_COMPONENT
KIND_COMPONENTVERSION = "component version"
KIND_RESOURCE = "component resource"
KIND_SOURCE = "component source"
KIND_REFERENCE = "component reference"
)

const ComponentDescriptorFileName = "component-descriptor.yaml"

Expand Down Expand Up @@ -716,7 +723,7 @@ func NewResourceMeta(name string, typ string, relation metav1.ResourceRelation)
}
}

type References []ComponentReference
type References []Reference

func (r References) Equivalent(o References) equivalent.EqualState {
return EquivalentElems(r, o)
Expand Down Expand Up @@ -753,10 +760,10 @@ func (r References) Copy() References {
return out
}

// ComponentReference describes the reference to another component in the registry.
// Reference describes the reference to another component in the registry.
// +k8s:deepcopy-gen=true
// +k8s:openapi-gen=true
type ComponentReference struct {
type Reference struct {
ElementMeta `json:",inline"`
// ComponentName describes the remote name of the referenced object
ComponentName string `json:"componentName"`
Expand All @@ -765,8 +772,11 @@ type ComponentReference struct {
Digest *metav1.DigestSpec `json:"digest,omitempty"`
}

func NewComponentReference(name, componentName, version string, extraIdentity metav1.Identity) *ComponentReference {
return &ComponentReference{
// Deprecated: use Reference.
type ComponentReference = Reference

func NewComponentReference(name, componentName, version string, extraIdentity metav1.Identity) *Reference {
return &Reference{
ElementMeta: ElementMeta{
Name: name,
Version: version,
Expand All @@ -776,41 +786,41 @@ func NewComponentReference(name, componentName, version string, extraIdentity me
}
}

func (r ComponentReference) String() string {
func (r Reference) String() string {
return fmt.Sprintf("%s[%s:%s]", r.Name, r.ComponentName, r.Version)
}

// WithVersion returns a new reference with a dedicated version.
func (o *ComponentReference) WithVersion(v string) *ComponentReference {
func (o *Reference) WithVersion(v string) *Reference {
n := o.Copy()
n.Version = v
return n
}

// WithExtraIdentity returns a new reference with a dedicated version.
func (o *ComponentReference) WithExtraIdentity(extras ...string) *ComponentReference {
func (o *Reference) WithExtraIdentity(extras ...string) *Reference {
n := o.Copy()
n.AddExtraIdentity(NewExtraIdentity(extras...))
return n
}

// Fresh returns a digest-free copy.
func (o *ComponentReference) Fresh() *ComponentReference {
func (o *Reference) Fresh() *Reference {
n := o.Copy()
n.Digest = nil
return n
}

func (r *ComponentReference) GetDigest() *metav1.DigestSpec {
func (r *Reference) GetDigest() *metav1.DigestSpec {
return r.Digest
}

func (r *ComponentReference) SetDigest(d *metav1.DigestSpec) {
func (r *Reference) SetDigest(d *metav1.DigestSpec) {
r.Digest = d
}

func (r *ComponentReference) Equivalent(e ElementMetaAccessor) equivalent.EqualState {
if o, ok := e.(*ComponentReference); !ok {
func (r *Reference) Equivalent(e ElementMetaAccessor) equivalent.EqualState {
if o, ok := e.(*Reference); !ok {
state := equivalent.StateNotLocalHashEqual()
if r.Digest != nil {
state = state.Apply(equivalent.StateNotArtifactEqual(true))
Expand All @@ -831,12 +841,12 @@ func (r *ComponentReference) Equivalent(e ElementMetaAccessor) equivalent.EqualS
}
}

func (r *ComponentReference) GetComponentName() string {
func (r *Reference) GetComponentName() string {
return r.ComponentName
}

func (r *ComponentReference) Copy() *ComponentReference {
return &ComponentReference{
func (r *Reference) Copy() *Reference {
return &Reference{
ElementMeta: *r.ElementMeta.Copy(),
ComponentName: r.ComponentName,
Digest: r.Digest.Copy(),
Expand Down
2 changes: 1 addition & 1 deletion api/ocm/compdesc/copy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ var _ = Describe("Component Descripor Copy Test Suitet", func() {
},
}
cd.References = compdesc.References{
compdesc.ComponentReference{
compdesc.Reference{
ElementMeta: compdesc.ElementMeta{},
ComponentName: "",
Digest: nil,
Expand Down
2 changes: 1 addition & 1 deletion api/ocm/compdesc/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func DefaultComponent(component *ComponentDescriptor) *ComponentDescriptor {
component.Sources = make([]Source, 0)
}
if component.References == nil {
component.References = make([]ComponentReference, 0)
component.References = make([]Reference, 0)
}
if component.Resources == nil {
component.Resources = make([]Resource, 0)
Expand Down
10 changes: 5 additions & 5 deletions api/ocm/compdesc/deprecated.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ func (cd *ComponentDescriptor) GetSourcesByName(name string, selectors ...Identi
// GetComponentReferences returns all component references that matches the given selectors.
//
// Deprectated: use GetReferences with appropriate selectors.
func (cd *ComponentDescriptor) GetComponentReferences(selectors ...IdentitySelector) ([]ComponentReference, error) {
refs := make([]ComponentReference, 0)
func (cd *ComponentDescriptor) GetComponentReferences(selectors ...IdentitySelector) ([]Reference, error) {
refs := make([]Reference, 0)
for _, ref := range cd.References {
ok, err := selector.MatchSelectors(ref.GetIdentity(cd.References), selectors...)
if err != nil {
Expand All @@ -220,13 +220,13 @@ func (cd *ComponentDescriptor) GetComponentReferences(selectors ...IdentitySelec
// GetComponentReferenceIndex returns the index of a given component reference.
// If the index is not found -1 is returned.
// Deprecated: use GetReferenceIndex.
func (cd *ComponentDescriptor) GetComponentReferenceIndex(ref ComponentReference) int {
func (cd *ComponentDescriptor) GetComponentReferenceIndex(ref Reference) int {
return cd.GetReferenceIndex(ref.GetMeta())
}

// GetReferenceAccessByIdentity returns a pointer to the reference that matches the given identity.
// Deprectated: use GetReferenceByIdentity.
func (cd *ComponentDescriptor) GetReferenceAccessByIdentity(id v1.Identity) *ComponentReference {
func (cd *ComponentDescriptor) GetReferenceAccessByIdentity(id v1.Identity) *Reference {
dig := id.Digest()
for i, ref := range cd.References {
if bytes.Equal(ref.GetIdentityDigest(cd.Resources), dig) {
Expand Down Expand Up @@ -270,7 +270,7 @@ func (cd *ComponentDescriptor) GetReferencesBySelectors(selectors []IdentitySele
if !ok {
continue
}
references = append(references, *selctx.ComponentReference)
references = append(references, *selctx.Reference)
}
if len(references) == 0 {
return references, NotFound
Expand Down
14 changes: 7 additions & 7 deletions api/ocm/compdesc/equal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,10 +487,10 @@ var _ = Describe("equivalence", func() {
})

Context("reference", func() {
var a, b *compdesc.ComponentReference
var a, b *compdesc.Reference

BeforeEach(func() {
a = &compdesc.ComponentReference{
a = &compdesc.Reference{
ElementMeta: compdesc.ElementMeta{
Name: "r1",
Version: "v1",
Expand Down Expand Up @@ -536,15 +536,15 @@ var _ = Describe("equivalence", func() {

BeforeEach(func() {
a = compdesc.References{
compdesc.ComponentReference{
compdesc.Reference{
ElementMeta: compdesc.ElementMeta{
Name: "s1",
Version: "v1",
Labels: labels.Copy(),
},
ComponentName: "c1",
},
compdesc.ComponentReference{
compdesc.Reference{
ElementMeta: compdesc.ElementMeta{
Name: "s2",
Version: "v1",
Expand Down Expand Up @@ -583,7 +583,7 @@ var _ = Describe("equivalence", func() {
})

It("handles additional entry", func() {
b = append(b, compdesc.ComponentReference{
b = append(b, compdesc.Reference{
ElementMeta: compdesc.ElementMeta{
Name: "s3",
ExtraIdentity: compdesc.NewExtraIdentity("platform", "linux"),
Expand All @@ -596,7 +596,7 @@ var _ = Describe("equivalence", func() {
})

It("handles additional entry without any other metadata", func() {
b = append(b, compdesc.ComponentReference{
b = append(b, compdesc.Reference{
ElementMeta: compdesc.ElementMeta{
Name: "s3",
ExtraIdentity: compdesc.NewExtraIdentity("platform", "linux"),
Expand All @@ -608,7 +608,7 @@ var _ = Describe("equivalence", func() {
})

It("handles additional entry without any other metadata", func() {
b = append(b, compdesc.ComponentReference{
b = append(b, compdesc.Reference{
ElementMeta: compdesc.ElementMeta{
Name: "s3",
ExtraIdentity: compdesc.NewExtraIdentity("platform", "linux"),
Expand Down
31 changes: 31 additions & 0 deletions api/ocm/compdesc/generic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package compdesc

import (
"encoding/json"

"github.com/mandelsoft/goutils/generics"
)

type GenericComponentDescriptor ComponentDescriptor

var (
_ json.Marshaler = (*GenericComponentDescriptor)(nil)
_ json.Unmarshaler = (*GenericComponentDescriptor)(nil)
)

func (g GenericComponentDescriptor) MarshalJSON() ([]byte, error) {
return Encode(generics.Pointer(ComponentDescriptor(g)), DefaultJSONCodec)
}

func (g *GenericComponentDescriptor) UnmarshalJSON(bytes []byte) error {
cd, err := Decode(bytes, DefaultJSONCodec)
if err != nil {
return err
}
*g = *((*GenericComponentDescriptor)(cd))
return nil
}

func (g *GenericComponentDescriptor) Descriptor() *ComponentDescriptor {
return (*ComponentDescriptor)(g)
}
12 changes: 6 additions & 6 deletions api/ocm/compdesc/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,24 +175,24 @@ func (cd *ComponentDescriptor) GetSourceIndex(src *SourceMeta) int {
}

// GetReferenceByIdentity returns reference that matches the given identity.
func (cd *ComponentDescriptor) GetReferenceByIdentity(id v1.Identity) (ComponentReference, error) {
func (cd *ComponentDescriptor) GetReferenceByIdentity(id v1.Identity) (Reference, error) {
dig := id.Digest()
for _, ref := range cd.References {
if bytes.Equal(ref.GetIdentityDigest(cd.Resources), dig) {
return ref, nil
}
}
return ComponentReference{}, errors.ErrNotFound(KIND_REFERENCE, id.String())
return Reference{}, errors.ErrNotFound(KIND_REFERENCE, id.String())
}

func (cd *ComponentDescriptor) SelectReferences(sel ...refsel.Selector) ([]ComponentReference, error) {
func (cd *ComponentDescriptor) SelectReferences(sel ...refsel.Selector) ([]Reference, error) {
err := selectors.ValidateSelectors(sel...)
if err != nil {
return nil, err
}

list := MapToSelectorElementList(cd.References)
result := []ComponentReference{}
result := []Reference{}
for _, r := range cd.References {
if len(sel) > 0 {
mr := MapToSelectorReference(&r)
Expand All @@ -207,8 +207,8 @@ func (cd *ComponentDescriptor) SelectReferences(sel ...refsel.Selector) ([]Compo
return result, nil
}

func (cd *ComponentDescriptor) GetReferences() []ComponentReference {
result := []ComponentReference{}
func (cd *ComponentDescriptor) GetReferences() []Reference {
result := []Reference{}
for _, r := range cd.References {
result = append(result, r)
}
Expand Down
Loading

0 comments on commit 74e50a9

Please sign in to comment.