Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Improve the repository context handling in the resolver #38

Merged
merged 1 commit into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bindings-go/apis/v2/accesstypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (O *OCIRegistryAccess) SetData(bytes []byte) error {
// OCIBlobType is the access type of a oci blob in a manifest.
const OCIBlobType = "ociBlob"

// OCIRegistryAccess describes the access for a oci registry.
// OCIBlobAccess describes the access for a oci registry.
type OCIBlobAccess struct {
ObjectType `json:",inline"`

Expand Down
2 changes: 1 addition & 1 deletion bindings-go/apis/v2/cdutils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func SetRawLabel(labels []v2.Label, name string, val []byte) []v2.Label {
})
}

// SetExtraIdentity sets a extra identity field of a identity object.
// SetExtraIdentityField sets a extra identity field of a identity object.
func SetExtraIdentityField(o *v2.IdentityObjectMeta, key, val string) {
if o.ExtraIdentity == nil {
o.ExtraIdentity = v2.Identity{}
Expand Down
13 changes: 6 additions & 7 deletions bindings-go/apis/v2/componentdescriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const (
ExternalRelation ResourceRelation = "external"
)

// Spec defines a versioned virtual component with a source and dependencies.
// ComponentDescriptor defines a versioned component with a source and dependencies.
// +k8s:deepcopy-gen=true
// +k8s:openapi-gen=true
type ComponentDescriptor struct {
Expand Down Expand Up @@ -93,7 +93,6 @@ type ComponentSpec struct {
Resources []Resource `json:"resources"`
}

// +k8s:deepcopy-gen=true
// RepositoryContext describes a repository context.
// +k8s:deepcopy-gen=true
// +k8s:openapi-gen=true
Expand All @@ -104,8 +103,8 @@ type RepositoryContext struct {
BaseURL string `json:"baseUrl"`
}

// +k8s:deepcopy-gen=true
// ObjectMeta defines a object that is uniquely identified by its name and version.
// +k8s:deepcopy-gen=true
type ObjectMeta struct {
// Name is the context unique name of the object.
Name string `json:"name"`
Expand Down Expand Up @@ -228,7 +227,7 @@ func (o *IdentityObjectMeta) SetExtraIdentity(identity Identity) {
o.ExtraIdentity = identity
}

// GetLabels returns the identity of the object.
// GetIdentity returns the identity of the object.
func (o *IdentityObjectMeta) GetIdentity() Identity {
identity := map[string]string{}
for k, v := range o.ExtraIdentity {
Expand All @@ -243,8 +242,8 @@ func (o *IdentityObjectMeta) GetIdentityDigest() []byte {
return o.GetIdentity().Digest()
}

// +k8s:deepcopy-gen=true
// ObjectType describes the type of a object
// +k8s:deepcopy-gen=true
type ObjectType struct {
// Type describes the type of the object.
Type string `json:"type"`
Expand Down Expand Up @@ -333,7 +332,7 @@ func NewEmptyUnstructured(ttype string) *UnstructuredAccessType {
return NewUnstructuredType(ttype, nil)
}

// NewCustomType creates a new custom typed object.
// NewUnstructuredType creates a new unstructured typed object.
func NewUnstructuredType(ttype string, data map[string]interface{}) *UnstructuredAccessType {
unstr := &UnstructuredAccessType{}
unstr.Object = data
Expand Down Expand Up @@ -529,7 +528,7 @@ func (o *ComponentReference) SetLabels(labels []Label) {
o.Labels = labels
}

// GetLabels returns the identity of the object.
// GetIdentity returns the identity of the object.
func (o *ComponentReference) GetIdentity() Identity {
identity := map[string]string{}
for k, v := range o.ExtraIdentity {
Expand Down
4 changes: 4 additions & 0 deletions bindings-go/apis/v2/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ package v2

// DefaultComponent applies defaults to a component
func DefaultComponent(component *ComponentDescriptor) error {
if component.RepositoryContexts == nil {
component.RepositoryContexts = make([]RepositoryContext, 0)
}
if component.Sources == nil {
component.Sources = make([]Source, 0)
}
Expand All @@ -30,6 +33,7 @@ func DefaultComponent(component *ComponentDescriptor) error {
return nil
}

// DefaultList defaults a list of components.
func DefaultList(list *ComponentDescriptorList) error {
for i, comp := range list.Components {
if len(comp.Metadata.Version) == 0 {
Expand Down
16 changes: 14 additions & 2 deletions bindings-go/apis/v2/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,21 @@ func NewNameSelector(name string) selector.Interface {

// GetEffectiveRepositoryContext returns the current active repository context.
func (c ComponentDescriptor) GetEffectiveRepositoryContext() RepositoryContext {
if len(c.RepositoryContexts) == 0 {
return RepositoryContext{}
}
return c.RepositoryContexts[len(c.RepositoryContexts)-1]
}

// InjectRepositoryContext appends the given repository context to components descriptor repository history.
// The context is not appended if the effective repository context already matches the current context.
func InjectRepositoryContext(cd *ComponentDescriptor, repoCtx RepositoryContext) {
effective := cd.GetEffectiveRepositoryContext()
if repoCtx != effective {
cd.RepositoryContexts = append(cd.RepositoryContexts, repoCtx)
}
}

// GetComponentReferences returns all component references that matches the given selectors.
func (c ComponentDescriptor) GetComponentReferences(selectors ...IdentitySelector) ([]ComponentReference, error) {
refs := make([]ComponentReference, 0)
Expand All @@ -99,7 +111,7 @@ func (c ComponentDescriptor) GetComponentReferencesByName(name string) ([]Compon
return c.GetComponentReferences(NewNameSelector(name))
}

// GetResourceByDefaultSelector returns resources that match the given selectors.
// GetResourceByJSONScheme returns resources that match the given selectors.
func (c ComponentDescriptor) GetResourceByJSONScheme(src interface{}) ([]Resource, error) {
sel, err := selector.NewJSONSchemaSelectorFromGoStruct(src)
if err != nil {
Expand Down Expand Up @@ -223,7 +235,7 @@ func (c ComponentDescriptor) GetResourcesByType(rtype string, selectors ...Ident
})
}

// GetResourcesByType returns all local and external resources of a specific resource type.
// GetResourcesByName returns all local and external resources with a name.
func (c ComponentDescriptor) GetResourcesByName(name string, selectors ...IdentitySelector) ([]Resource, error) {
return c.getResourceBySelectors(
append(selectors, NewNameSelector(name)),
Expand Down
2 changes: 1 addition & 1 deletion bindings-go/apis/v2/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (c *ComponentDescriptorList) GetComponent(name, version string) (ComponentD
return ComponentDescriptor{}, errors.New("NotFound")
}

// GetComponent returns all components that match the given name.
// GetComponentByName returns all components that match the given name.
func (c *ComponentDescriptorList) GetComponentByName(name string) []ComponentDescriptor {
comps := make([]ComponentDescriptor, 0)
for _, comp := range c.Components {
Expand Down
2 changes: 1 addition & 1 deletion bindings-go/ctf/componentarchive.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func (ca *ComponentArchive) AddSource(src *v2.Source, info BlobInfo, reader io.R
return nil
}

// AddResource adds a blob resource to the current archive.
// AddResourceFromResolver adds a blob resource to the current archive.
// If the specified resource already exists it will be overwritten.
func (ca *ComponentArchive) AddResourceFromResolver(ctx context.Context, res *v2.Resource, resolver BlobResolver) error {
if res == nil {
Expand Down
9 changes: 5 additions & 4 deletions bindings-go/ctf/ctf.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ var UnsupportedResolveType = errors.New("UnsupportedResolveType")

// ComponentResolver describes a general interface to resolve a component descriptor
type ComponentResolver interface {
Resolve(ctx context.Context, repoCtx v2.RepositoryContext, name, version string) (*v2.ComponentDescriptor, BlobResolver, error)
Resolve(ctx context.Context, repoCtx v2.RepositoryContext, name, version string) (*v2.ComponentDescriptor, error)
ResolveWithBlobResolver(ctx context.Context, repoCtx v2.RepositoryContext, name, version string) (*v2.ComponentDescriptor, BlobResolver, error)
}

// BlobResolver defines a resolver that can fetch
Expand Down Expand Up @@ -151,7 +152,7 @@ func (ctf *CTF) AddComponentArchive(ca *ComponentArchive, format ArchiveFormat)
return ctf.AddComponentArchiveWithName(filename, ca, format)
}

// AddComponentArchive adds or updates a component archive in the ctf archive.
// AddComponentArchiveWithName adds or updates a component archive in the ctf archive.
// The archive is added to the ctf with the given name
func (ctf *CTF) AddComponentArchiveWithName(filename string, ca *ComponentArchive, format ArchiveFormat) error {
file, err := ctf.tempFs.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
Expand Down Expand Up @@ -294,7 +295,7 @@ func (a *AggregatedBlobResolver) getResolver(res v2.Resource) (BlobResolver, err
return nil, UnsupportedResolveType
}

// AggregateBlobResolvers aggregartes two resolvers to one by using aggregated blob resolver.
// AggregateBlobResolvers aggregates two resolvers to one by using aggregated blob resolver.
func AggregateBlobResolvers(a, b BlobResolver) (BlobResolver, error) {
aggregated, ok := a.(*AggregatedBlobResolver)
if ok {
Expand All @@ -312,6 +313,6 @@ func AggregateBlobResolvers(a, b BlobResolver) (BlobResolver, error) {
return aggregated, nil
}

// create a new aggreagted resolver if neither a nor b are aggregations
// create a new aggregated resolver if neither a nor b are aggregations
return NewAggregatedBlobResolver(a, b)
}
81 changes: 81 additions & 0 deletions bindings-go/ctf/ctfutils/ctfutils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: 2021 SAP SE or an SAP affiliate company and Gardener contributors.
//
// SPDX-License-Identifier: Apache-2.0

package ctfutils

import (
"context"
"fmt"

cdv2 "github.com/gardener/component-spec/bindings-go/apis/v2"
"github.com/gardener/component-spec/bindings-go/ctf"
)

// ResolveList resolves all component descriptors of a given root component descriptor.
func ResolveList(ctx context.Context,
resolver ctf.ComponentResolver,
repoCtx cdv2.RepositoryContext,
name,
version string) (*cdv2.ComponentDescriptorList, error) {

list := &cdv2.ComponentDescriptorList{}
err := ResolveRecursive(ctx, resolver, repoCtx, name, version, func(cd *cdv2.ComponentDescriptor) (stop bool, err error) {
if _, err := list.GetComponent(cd.Name, cd.Version); err != nil {
list.Components = append(list.Components, *cd)
}
return false, nil
})
if err != nil {
return nil, err
}
return list, nil
}

// ResolvedCallbackFunc describes a function that is called when a component descriptor is resolved.
// The function can optionally return an bool which when set to true stops the resolve of further component descriptors
type ResolvedCallbackFunc func(descriptor *cdv2.ComponentDescriptor) (stop bool, err error)

// ResolveRecursive recursively resolves all component descriptors dependencies.
// Everytime a new component descriptor is resolved the given callback function is called.
// The resolve of further components can be stopped when
// - the callback returns true for the stop parameter
// - the callback returns an error
// - all components are successfully resolved.
func ResolveRecursive(ctx context.Context, resolver ctf.ComponentResolver, repoCtx cdv2.RepositoryContext, name, version string, cb ResolvedCallbackFunc) error {
cd, err := resolver.Resolve(ctx, repoCtx, name, version)
if err != nil {
return fmt.Errorf("unable to resolve component descriptor for %q %q %q: %w", repoCtx.BaseURL, name, version, err)
}
stop, err := cb(cd)
if err != nil {
return fmt.Errorf("error while calling callback for %q %q %q: %w", repoCtx.BaseURL, name, version, err)
}
if stop {
return nil
}
return resolveRecursive(ctx, resolver, repoCtx, cd, cb)
}

func resolveRecursive(ctx context.Context, resolver ctf.ComponentResolver, repoCtx cdv2.RepositoryContext, cd *cdv2.ComponentDescriptor, cb ResolvedCallbackFunc) error {
components := make([]*cdv2.ComponentDescriptor, len(cd.ComponentReferences))
for _, ref := range cd.ComponentReferences {
cd, err := resolver.Resolve(ctx, repoCtx, ref.ComponentName, ref.Version)
if err != nil {
return fmt.Errorf("unable to resolve component descriptor for %q %q %q: %w", repoCtx.BaseURL, ref.ComponentName, ref.Version, err)
}
stop, err := cb(cd)
if err != nil {
return fmt.Errorf("error while calling callback for %q %q %q: %w", repoCtx.BaseURL, ref.ComponentName, ref.Version, err)
}
if stop {
return nil
}
}
for _, ref := range components {
if err := resolveRecursive(ctx, resolver, repoCtx, ref, cb); err != nil {
return err
}
}
return nil
}
1 change: 1 addition & 0 deletions bindings-go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.14

require (
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v0.4.0
github.com/mandelsoft/vfs v0.0.0-20201002134249-3c471f64a4d1
github.com/onsi/ginkgo v1.14.0
github.com/onsi/gomega v1.10.1
Expand Down
2 changes: 2 additions & 0 deletions bindings-go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
Expand Down
38 changes: 36 additions & 2 deletions bindings-go/oci/oci_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
package oci_test

import (
"context"
"io"
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
ocispecv1 "github.com/opencontainers/image-spec/specs-go/v1"

cdv2 "github.com/gardener/component-spec/bindings-go/apis/v2"
"github.com/gardener/component-spec/bindings-go/oci"
Expand All @@ -21,7 +24,6 @@ func TestConfig(t *testing.T) {

var _ = Describe("helper", func(){


Context("OCIRef", func() {

It("should correctly parse a repository url without a protocol and a component", func() {
Expand Down Expand Up @@ -52,7 +54,39 @@ var _ = Describe("helper", func(){
Expect(ref).To(Equal("example.com:443/component-descriptors/somecomp:v0.0.0"))
})


})

})

// testClient describes a test oci client.
type testClient struct {
getManifest func(ctx context.Context, ref string) (*ocispecv1.Manifest, error)
fetch func(ctx context.Context, ref string, desc ocispecv1.Descriptor, writer io.Writer) error
}

var _ oci.Client = &testClient{}

func (t testClient) GetManifest(ctx context.Context, ref string) (*ocispecv1.Manifest, error) {
return t.getManifest(ctx, ref)
}

func (t testClient) Fetch(ctx context.Context, ref string, desc ocispecv1.Descriptor, writer io.Writer) error {
return t.fetch(ctx, ref, desc, writer)
}

// testCache describes a test resolve cache.
type testCache struct {
get func (ctx context.Context, repoCtx cdv2.RepositoryContext, name, version string) (*cdv2.ComponentDescriptor, error)
store func(ctx context.Context, descriptor *cdv2.ComponentDescriptor) error
}

var _ oci.Cache = &testCache{}

func (t testCache) Get(ctx context.Context, repoCtx cdv2.RepositoryContext, name, version string) (*cdv2.ComponentDescriptor, error) {
return t.get(ctx, repoCtx, name, version)
}

func (t testCache) Store(ctx context.Context, descriptor *cdv2.ComponentDescriptor) error {
return t.store(ctx, descriptor)
}

Loading