From edcca5bb972a93a94cc2714cae54db0f41f5f6dc Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Fri, 17 Dec 2021 09:49:11 +0100 Subject: [PATCH 1/3] oci artefact spec --- doc/oci.rst | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/doc/oci.rst b/doc/oci.rst index 6fb2b841..19fcee33 100644 --- a/doc/oci.rst +++ b/doc/oci.rst @@ -74,7 +74,8 @@ artefact archives. Component Archive ................. -So far there is only a specification for the format for a component artefact. +The component archive contains a first file ``component-descriptor.yaml`` +which contains the component descriptor of the component version. .. code-block:: @@ -95,7 +96,19 @@ OCI Artefact ............ A similar format for standard OCI Artefacts (including OCI Images as special case) -could look like this +always contains the file ``artefact-descriptor.yaml`` as first file. +It is a YAML or JSON file describing the artefact meta data. Additionally it may contain +signatures like the component descriptor. + +.. code-block:: + apiVersion: ocm.gardener.cloud/v1 + kind: ArtefactDescriptor + metadata: + name: + version: + +Then it contains the files belonging to this oci artefact. It is the +``oci-artefact.json`` and the blobs described by the oci-artefact. .. code-block:: @@ -106,13 +119,10 @@ could look like this ├── ... └── blobn -Like the component descriptor the additional file ``artefact-descriptor.yaml`` -described the artefact name and version. The other files are just taken -from the OCI artefact api. The blob names should be the correct OCI -digests used in the ``oci-manifest.json``. +The blob names should be the correct OCI digests used in the ``oci-manifest.json``. -The artefact descriptor must be the first entry in the tar archive to -support streaming, followed by the oci manifest. +The artefact descriptor must be the first entry in the tar archive followed by the +oci manifest to support streaming. OCI related Access Types ------------------------ From 2c1458a35347e19de385db56a2398e51d4547afd Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Fri, 17 Dec 2021 11:33:51 +0100 Subject: [PATCH 2/3] rework motivation --- doc/ResourceAccess.png | 3 + doc/Transport.png | 3 + doc/conf.py | 2 +- doc/index.rst | 18 ++--- doc/motivation.rst | 146 +++++++++++++++++++++++++++++++---------- doc/oci.rst | 1 + 6 files changed, 130 insertions(+), 43 deletions(-) create mode 100755 doc/ResourceAccess.png create mode 100755 doc/Transport.png diff --git a/doc/ResourceAccess.png b/doc/ResourceAccess.png new file mode 100755 index 00000000..5502adfb --- /dev/null +++ b/doc/ResourceAccess.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:123e1f6193501e57131763ad91591a3985034691ba2c51910df45ae865e8dc00 +size 103190 diff --git a/doc/Transport.png b/doc/Transport.png new file mode 100755 index 00000000..547ba618 --- /dev/null +++ b/doc/Transport.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:87ff95ed6a11ba498a22f6fde441db2d0cdaef6afe73001871402042664f86f4 +size 82011 diff --git a/doc/conf.py b/doc/conf.py index 11df1741..caddbb5e 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -17,7 +17,7 @@ # -- Project information ----------------------------------------------------- -project = 'Gardener Component-Descriptor Contract and Specification' +project = 'Open Component Model Contract and Specification' copyright = '2020, The Gardener Team' author = 'The Gardener Team' diff --git a/doc/index.rst b/doc/index.rst index 98a83a97..73443690 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -3,18 +3,18 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Gardener Component-Descriptor Contract and Specification -======================================================== +Open Component Model +==================== -This document describes the contract components adhere to in order to declare in a -machine-readable way dependency graphs of multiple components and their resources. +This document describes the Open Component Model (OCM), its idea and reasoning, scope, contract +and some tools working on top of this model. -This contract encompasses: - -- technical format specification -- schema specification (JSON-schema) -- semantical specification +The component model provides a machine-readable way to describe versioned artefact sets that finally +build installable software packages, that can be transported among public and local repository contexts. +It is a sound technology-independent basis for cooperating tools to access artefacts in a +locaction-agnostic manner. This can be used to run tools and processes uniformly for the +same software in various, even fenced environments. .. toctree:: :maxdepth: 2 diff --git a/doc/motivation.rst b/doc/motivation.rst index ea9d68f7..4db275e3 100644 --- a/doc/motivation.rst +++ b/doc/motivation.rst @@ -1,7 +1,8 @@ -Motivation and Scope -==================== +Motivation +========== -Operating Software installations both for Cloud and on-premises covers many aspects: +Operating software installations both for Cloud and on-premises covers +many aspects: - how, when and where are the technical artefacts created - how are technical artefacts stored and accessed @@ -9,46 +10,102 @@ Operating Software installations both for Cloud and on-premises covers many aspe - how is the configuration managed - when are technical artefacts deployed - where and how are those artefacts deployed -- which other software installations are required and how are they deployed and accessed +- which other software installations are required and how are they + deployed and accessed -The overall problem domain has a complexity that make it challenging to be solved as a whole. -However, the problem domain can be divided into two disjoint subdomains: +The overall problem domain has a complexity that makes it +challenging to be solved as a whole. However, the problem domain +can be divided into two disjoint subdomains: - production of software artefacts -- deployment and lifecycle management of installations - -The elements transitioning between those two subdomains are synchronisation -data ("when things should happen") and technical artefacts and their purposes. - -By standardising those elements, it is possible to decouple those two aspects. This allows -to split the overall complexity into smaller parts. By this, the overall complexity can also be -reduced. - -The CNUDIE Component Model defines a standardisation of the latter (technical -artefacts and their purposes). The major goal that is tried to be achieved by -this standardisation is to allow for components and their artefacts to be -umambiguously addressed and accessed in a location- and technology-agnostic -manner. This should work for both global and local or even private environments. +- processes acting on those artefact sets like compliance + processes, transport, deployment and lifecycle management of + installations + +The elements transitioning between those two subdomains are +synchronisation data ("when things should happen") and technical +artefacts and their purposes. + +By standardising those elements, it is possible to decouple those +two aspects. This allows to split the overall complexity into +smaller parts. The involved artefacts are basically some kind +of source of truth, all processes during a software lifecycle +finally cooperate on these elements, they are generated by a build, +matter of compliance assessment, the have to transported and +deployed, and finally the data controlling processes like +deployment can be expressed by artefacts, also. Because of +this, it seems to be a good idea to standardize the description +and handling of software artefacts. By this, independent tools +can cooperate on such a view to software and the overall complexity +can be reduced, . + +When dealing with aspects of software or software artefacts +like delivery, life cycle management or security aspects it is +important to reliably build the bridge between uniquely denoting +or identifying software or software parts and the real, effective +technical content behind the naming scheme. +This must be combined with the possibility to describe the access +of the real content just by the naming scheme in any kind of storage +environment, be it public or fenced local ones, +and a reliable way to transport software among such environments. +At the same time not only the sole executable artefacts must be +considered, but all other kinds of meta data or accompanying information +used to describe the artefacts, their meaning, deployment and lifecycle +aspects. + +Although container based software systems, especially Kubernetes, +are increasingly displacing other other runtime models there will for +sure always be competing or specialized or even new upcoming ones in +the future, which must potentially be commonly described in one closed +model. Therefore such a software description model must not be related to +dedicated technologies, be it content types, runtime models or tools +working the the denoted content. + +The Open Component Model will offer a sound common technology-agnostic +basis to denote and describe the access of any kind of software by grouping +typed artefacts and establishing a hierarchical naming scheme, which is +applicable for all content that can reliably represented as blobs. + +Like the today's generic file system models it can be used to store +and access any kind of data in any suitable repository or even archives +or regular file systems. + +It acts as a common scheme for any kind of tool that can interpret or deal +with the typed artefact blobs with its own semantic to fulfill its tasks. +The common naming scheme allows to correlate artefacts described by +the model +with other tool specific data at API level and therefore enables +the cooperation of decoupled, independent tools by always keeping +the connection to the single truth, the artefacts and artefacts groups +they deal with. + +Establishing a common, technology-agnostic and extensible model to +describe software and its artifacts provides software developers, +software vendors, and their partners with a unique way to consistently +build, deliver and deploy compliant software, based on any technology, +to any environment. Core Concepts ------------- -:ref:`Components ` in CNUDIE are semantical entities with a +:ref:`Components ` in OCM are semantical entities with a certain semantical focus, as part of a software product. They are typically -built from :ref:`Sources `, which are being conciously developed. They consist of a set of (component) versions. Each version is described by a :ref:`Component Descriptor `, which describes the included set of artefacts. `Component Descriptors` are stored in a -:ref:`Component Repository <_concepts_component_repositories` in a standardised +:ref:`Component Repository ` in a standardized way. Within such a component repository, component descriptors are addressed by their component name and version. By separating the storage locations (component repository) from the component version identity, in combination with a defined addressing scheme, it is possible to -access component descriptors in a component repository, in a location-independent manner. -This can be leveraged to replicate component descriptors between component repositories. +access component descriptors uniquely in any component repository, in a +location-independent manner. +This can be leveraged to replicate component descriptors and the described artefacts +between component repositories. Each of the artefacts declared in a `Component Descriptor` has an `identity`, an `access` description and a `type`. `Artefact identities` can be used to reference an artefact in @@ -56,12 +113,16 @@ the context of the declaring component descriptor. The `Artefact type` defines h artefact is to be interpreted. The `access Description` defines from where the artefact can be retrieved. +.. image:: Transport.png + When replicating component descriptors and their artefacts, the artefacts' `access` descriptions may be changed. However, `artefact types` and `artefact identities` always remain unchanged. -The CNUDIE Component Model can roughly be compared to a filesystem "living" in an arbitrary +The Open Component Model can roughly be compared to a filesystem "living" in an arbitrary storage (e.g. a blobstore, oci-registry, archive, ..). +.. image:: ResourceAccess.png + Starting from an arbitrary component repository used as root repository it is possible to access any artefact described by the component model as long as the dedicated component version has been imported into this repository. The @@ -78,20 +139,39 @@ feature a local identity in the describing component descriptor. Scope Definition ---------------- -The CNUDIE Component model intends to solve the problem of addressing, +The Open Component model intends to solve the problem of addressing, identifying, and accessing artefacts for software components, relative to an arbitrary component repository. By that, it also enables the transport of software components between component repositories. Through the standardisation of structure and `access` to artefacts, it can serve as an -interface to any operations that need to interact with the content. This allows -for tools operating against this interface to be implemented in a re-usable, and -technology-agnostic manner (examples being transport, compliance and security -scanning, codesigning, ..). +interface to any operation or tool that needs to interact with the content. +This allows for tools operating against this interface to be implemented in a +re-usable, and technology-agnostic manner (examples being transport, +compliance and security scanning, codesigning, ..). Higherlevel functionality, such as deployment, or lifecycle-management aspects are -out of the scope the CNUDIE Component Model targets. Data for such aspects (for example -a deployment blueprint) can, however, be described by the CNUDIE Component Model +out of the scope the Open Component Model targets. However, it acts as a container to +host (access, transport, ...) information for those processes. Data for such +aspects (for example a deployment blueprint) can, be described by the Open Component Model as dedicated typed artefacts. This is equivalent to e.g. adding a `Makefile` into a filesystem. The filesystem does not "know" about the semantics of the `Makefile` (including, e.g. declared dependencies towards other files). + +An example for such a tool is the Landscaper. +With the Landscaper, a new open, technology-agnostic and extensible deployment +control tool is established on top of this software description model. +Based on deployment descriptions, the Blueprints, and additional artefact information +taken from the component model, it orchestrates and configures desired states in +a Kubernetes-like manner that are finally handled by type specific Deployers which +control the actual technology-specific deployment steps. Based on a very small set +of standard Kubernetes-based deployers, any other kind of deployer can be added as +part of the deployment process to support deployments in any technical or even +fenced environment. The complete data plane is maintained in a Kubernetes system +and can be maintained by traditional GitOps processes configuring installations +based on artefacts uniformly described by and accessed using the open component model. + +The combination of both parts, the Open Component Model and the Landscaper makes +complete heterogeneous scenarios, including the required software parts and their +orchestrations, transportable among and executable in any local and independent +repository landscapes, controlled by local GitOps processes. diff --git a/doc/oci.rst b/doc/oci.rst index 19fcee33..b6037141 100644 --- a/doc/oci.rst +++ b/doc/oci.rst @@ -101,6 +101,7 @@ It is a YAML or JSON file describing the artefact meta data. Additionally it may signatures like the component descriptor. .. code-block:: + apiVersion: ocm.gardener.cloud/v1 kind: ArtefactDescriptor metadata: From 0ae420fb9ddbfbd763f66bd928c4d0aaf0721825 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Tue, 11 Jan 2022 16:11:53 +0100 Subject: [PATCH 3/3] align unstructured types object --- bindings-go/apis/v2/codecs.go | 24 +++++++++++++++++++ bindings-go/apis/v2/helper.go | 11 +++++---- bindings-go/apis/v2/unstructured.go | 10 ++++---- bindings-go/apis/v2/v2_suite_test.go | 4 ++-- .../apis/v2/validation/validation_test.go | 4 ++-- bindings-go/ctf/componentarchive.go | 6 ++--- bindings-go/ctf/ctf.go | 4 ++-- bindings-go/ctf/listresolver.go | 2 +- bindings-go/ctf/listresolver_test.go | 16 ++++++------- bindings-go/examples/main.go | 2 +- bindings-go/go.mod | 1 + bindings-go/oci/manifest.go | 14 +++++------ bindings-go/oci/oci_suite_test.go | 9 ++++--- bindings-go/oci/resolve.go | 14 +++++------ bindings-go/oci/resolve_test.go | 18 +++++++------- bindings-go/utils/selector/selector.go | 2 +- .../component-descriptor-v2-schema.yaml | 1 - 17 files changed, 84 insertions(+), 58 deletions(-) diff --git a/bindings-go/apis/v2/codecs.go b/bindings-go/apis/v2/codecs.go index 57f198e3..23f11300 100644 --- a/bindings-go/apis/v2/codecs.go +++ b/bindings-go/apis/v2/codecs.go @@ -17,6 +17,8 @@ package v2 import ( "encoding/json" "fmt" + + "github.com/modern-go/reflect2" ) // KnownTypeValidationFunc defines a function that can validate types. @@ -133,6 +135,8 @@ func NewCodec(knownTypes KnownTypes, defaultCodec TypedObjectCodec, validationFu } } +var defaultCodec = NewDefaultCodec() + // Decode unmarshals a unstructured typed object into a TypedObjectAccessor. // The given known types are used to decode the data into a specific. // The given defaultCodec is used if no matching type is known. @@ -176,8 +180,28 @@ func (c *codec) Encode(acc TypedObjectAccessor) ([]byte, error) { return codec.Encode(acc) } +func DecodeInto(obj TypedObjectAccessor, into TypedObjectAccessor) error { + un, err := ToUnstructuredTypedObject(nil, obj) + if err != nil { + return err + } + if reflect2.IsNil(un) { + return fmt.Errorf("no accessor") + } + return un.DecodeInto(into) +} + // ToUnstructuredTypedObject converts a typed object to a unstructured object. func ToUnstructuredTypedObject(codec TypedObjectCodec, obj TypedObjectAccessor) (*UnstructuredTypedObject, error) { + if obj == nil { + return nil, nil + } + if un, ok := obj.(*UnstructuredTypedObject); ok { + return un, nil + } + if codec == nil { + codec = defaultCodec + } data, err := codec.Encode(obj) if err != nil { return nil, err diff --git a/bindings-go/apis/v2/helper.go b/bindings-go/apis/v2/helper.go index 8d037e0f..e057802a 100644 --- a/bindings-go/apis/v2/helper.go +++ b/bindings-go/apis/v2/helper.go @@ -72,7 +72,7 @@ func NewNameSelector(name string) selector.Interface { } // GetEffectiveRepositoryContext returns the current active repository context. -func (c ComponentDescriptor) GetEffectiveRepositoryContext() *UnstructuredTypedObject { +func (c ComponentDescriptor) GetEffectiveRepositoryContext() Repository { if len(c.RepositoryContexts) == 0 { return nil } @@ -82,13 +82,16 @@ func (c ComponentDescriptor) GetEffectiveRepositoryContext() *UnstructuredTypedO // 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 TypedObjectAccessor) error { - effective := cd.GetEffectiveRepositoryContext() + effective, err := NewUnstructured(cd.GetEffectiveRepositoryContext()) + if err != nil { + return err + } uRepoCtx, err := NewUnstructured(repoCtx) if err != nil { return err } - if !UnstructuredTypesEqual(effective, &uRepoCtx) { - cd.RepositoryContexts = append(cd.RepositoryContexts, &uRepoCtx) + if !UnstructuredTypesEqual(effective, uRepoCtx) { + cd.RepositoryContexts = append(cd.RepositoryContexts, uRepoCtx) } return nil } diff --git a/bindings-go/apis/v2/unstructured.go b/bindings-go/apis/v2/unstructured.go index 771f3208..c0c8dd5c 100644 --- a/bindings-go/apis/v2/unstructured.go +++ b/bindings-go/apis/v2/unstructured.go @@ -54,16 +54,16 @@ func TypedObjectEqual(a, b TypedObjectAccessor) bool { if err != nil { return false } - return UnstructuredTypesEqual(&uA, &uB) + return UnstructuredTypesEqual(uA, uB) } // NewUnstructured creates a new unstructured object from a typed object using the default codec. -func NewUnstructured(obj TypedObjectAccessor) (UnstructuredTypedObject, error) { - uObj, err := ToUnstructuredTypedObject(NewDefaultCodec(), obj) +func NewUnstructured(obj TypedObjectAccessor) (*UnstructuredTypedObject, error) { + uObj, err := ToUnstructuredTypedObject(nil, obj) if err != nil { - return UnstructuredTypedObject{}, nil + return &UnstructuredTypedObject{}, err } - return *uObj, nil + return uObj, nil } // NewEmptyUnstructured creates a new typed object without additional data. diff --git a/bindings-go/apis/v2/v2_suite_test.go b/bindings-go/apis/v2/v2_suite_test.go index 8355117e..13ead66c 100644 --- a/bindings-go/apis/v2/v2_suite_test.go +++ b/bindings-go/apis/v2/v2_suite_test.go @@ -60,7 +60,7 @@ var _ = Describe("Helper", func() { }, }, Relation: v2.ExternalRelation, - Access: &unstrucOCIRegistry1, + Access: unstrucOCIRegistry1, } ociRegistry2 = &v2.OCIRegistryAccess{ ObjectType: v2.ObjectType{ @@ -80,7 +80,7 @@ var _ = Describe("Helper", func() { }, }, Relation: v2.ExternalRelation, - Access: &unstrucOCIRegistry2, + Access: unstrucOCIRegistry2, } comp = &v2.ComponentDescriptor{ diff --git a/bindings-go/apis/v2/validation/validation_test.go b/bindings-go/apis/v2/validation/validation_test.go index 62c59cb7..8e6cb6df 100644 --- a/bindings-go/apis/v2/validation/validation_test.go +++ b/bindings-go/apis/v2/validation/validation_test.go @@ -58,7 +58,7 @@ var _ = Describe("Validation", func() { Version: "1.2.3", }, Relation: v2.ExternalRelation, - Access: &unstrucOCIRegistry1, + Access: unstrucOCIRegistry1, } ociRegistry2 = &v2.OCIRegistryAccess{ ObjectType: v2.ObjectType{ @@ -74,7 +74,7 @@ var _ = Describe("Validation", func() { Version: "1.2.3", }, Relation: v2.ExternalRelation, - Access: &unstrucOCIRegistry2, + Access: unstrucOCIRegistry2, } comp = &v2.ComponentDescriptor{ diff --git a/bindings-go/ctf/componentarchive.go b/bindings-go/ctf/componentarchive.go index a4a70ce5..d1d153ac 100644 --- a/bindings-go/ctf/componentarchive.go +++ b/bindings-go/ctf/componentarchive.go @@ -166,7 +166,7 @@ func (ca *ComponentArchive) AddResource(res *v2.Resource, info BlobInfo, reader if err != nil { return fmt.Errorf("unable to convert local filesystem type to untructured type: %w", err) } - res.Access = &unstructuredType + res.Access = unstructuredType if id == -1 { ca.ComponentDescriptor.Resources = append(ca.ComponentDescriptor.Resources, *res) @@ -209,7 +209,7 @@ func (ca *ComponentArchive) AddSource(src *v2.Source, info BlobInfo, reader io.R if err != nil { return fmt.Errorf("unable to convert local filesystem type to untructured type: %w", err) } - src.Access = &unstructuredType + src.Access = unstructuredType if id == -1 { ca.ComponentDescriptor.Sources = append(ca.ComponentDescriptor.Sources, *src) @@ -257,7 +257,7 @@ func (ca *ComponentArchive) AddResourceFromResolver(ctx context.Context, res *v2 if err != nil { return fmt.Errorf("unable to convert local filesystem type to untructured type: %w", err) } - res.Access = &unstructuredType + res.Access = unstructuredType if id == -1 { ca.ComponentDescriptor.Resources = append(ca.ComponentDescriptor.Resources, *res) diff --git a/bindings-go/ctf/ctf.go b/bindings-go/ctf/ctf.go index 9c6ffe63..66705d96 100644 --- a/bindings-go/ctf/ctf.go +++ b/bindings-go/ctf/ctf.go @@ -91,10 +91,10 @@ const ( ) type CTF struct { - fs vfs.FileSystem + fs vfs.FileSystem ctfPath string tempDir string - tempFs vfs.FileSystem + tempFs vfs.FileSystem } // NewCTF reads a CTF archive from a file. diff --git a/bindings-go/ctf/listresolver.go b/bindings-go/ctf/listresolver.go index dd130fc7..b7bbfc52 100644 --- a/bindings-go/ctf/listresolver.go +++ b/bindings-go/ctf/listresolver.go @@ -12,7 +12,7 @@ import ( // ListResolver describes a ComponentResolver using a list of Component Descriptors type ListResolver struct { - List *cdv2.ComponentDescriptorList + List *cdv2.ComponentDescriptorList blobResolver *AggregatedBlobResolver } diff --git a/bindings-go/ctf/listresolver_test.go b/bindings-go/ctf/listresolver_test.go index cb8bab1a..a3679124 100644 --- a/bindings-go/ctf/listresolver_test.go +++ b/bindings-go/ctf/listresolver_test.go @@ -30,13 +30,13 @@ var _ = Describe("ListResolver", func() { cd.Name = "example.com/a" cd.Version = "0.0.0" repoCtx, _ := cdv2.NewUnstructured(cdv2.NewOCIRegistryRepository("example.com/registry", "")) - cd.RepositoryContexts = append(cd.RepositoryContexts, &repoCtx) + cd.RepositoryContexts = append(cd.RepositoryContexts, repoCtx) lr, err := ctf.NewListResolver(&cdv2.ComponentDescriptorList{ Components: []cdv2.ComponentDescriptor{cd}, }) Expect(err).ToNot(HaveOccurred()) - res, err := lr.Resolve(context.TODO(), &repoCtx, "example.com/a", "0.0.0") + res, err := lr.Resolve(context.TODO(), repoCtx, "example.com/a", "0.0.0") Expect(err).ToNot(HaveOccurred()) Expect(res.Name).To(Equal("example.com/a")) }) @@ -46,7 +46,7 @@ var _ = Describe("ListResolver", func() { cd.Name = "example.com/a" cd.Version = "0.0.0" repoCtx, _ := cdv2.NewUnstructured(cdv2.NewOCIRegistryRepository("example.com/registry", "")) - cd.RepositoryContexts = append(cd.RepositoryContexts, &repoCtx) + cd.RepositoryContexts = append(cd.RepositoryContexts, repoCtx) cd2 := cdv2.ComponentDescriptor{} cd2.Name = "example.com/a" @@ -57,20 +57,20 @@ var _ = Describe("ListResolver", func() { }, } repoCtx2, _ := cdv2.NewUnstructured(cdv2.NewOCIRegistryRepository("example.com/registry2", "")) - cd2.RepositoryContexts = append(cd.RepositoryContexts, &repoCtx2) + cd2.RepositoryContexts = append(cd.RepositoryContexts, repoCtx2) lr, err := ctf.NewListResolver(&cdv2.ComponentDescriptorList{ Components: []cdv2.ComponentDescriptor{cd, cd2}, }) Expect(err).ToNot(HaveOccurred()) - res, err := lr.Resolve(context.TODO(), &repoCtx2, "example.com/a", "0.0.0") + res, err := lr.Resolve(context.TODO(), repoCtx2, "example.com/a", "0.0.0") Expect(err).ToNot(HaveOccurred()) Expect(res.Name).To(Equal("example.com/a")) Expect(res.Labels).To(ContainElement(cdv2.Label{ Name: "test", })) - res, err = lr.Resolve(context.TODO(), &repoCtx, "example.com/a", "0.0.0") + res, err = lr.Resolve(context.TODO(), repoCtx, "example.com/a", "0.0.0") Expect(err).ToNot(HaveOccurred()) Expect(res.Name).To(Equal("example.com/a")) Expect(res.Labels).ToNot(ContainElement(cdv2.Label{ @@ -83,13 +83,13 @@ var _ = Describe("ListResolver", func() { cd.Name = "example.com/a" cd.Version = "0.0.0" repoCtx, _ := cdv2.NewUnstructured(cdv2.NewOCIRegistryRepository("example.com/registry", "")) - cd.RepositoryContexts = append(cd.RepositoryContexts, &repoCtx) + cd.RepositoryContexts = append(cd.RepositoryContexts, repoCtx) lr, err := ctf.NewListResolver(&cdv2.ComponentDescriptorList{ Components: []cdv2.ComponentDescriptor{cd}, }) Expect(err).ToNot(HaveOccurred()) - _, err = lr.Resolve(context.TODO(), &repoCtx, "example.com/b", "0.0.0") + _, err = lr.Resolve(context.TODO(), repoCtx, "example.com/b", "0.0.0") Expect(err).To(HaveOccurred()) Expect(err).To(Equal(ctf.NotFoundError)) }) diff --git a/bindings-go/examples/main.go b/bindings-go/examples/main.go index e2f10c6f..d2b6d681 100644 --- a/bindings-go/examples/main.go +++ b/bindings-go/examples/main.go @@ -80,7 +80,7 @@ component: // get the latest repository context. // the context is returned as unstructured object (similar to the access types) as differnt repository types // with different attributes are possible. - unstructuredRepoCtx := component.GetEffectiveRepositoryContext() + unstructuredRepoCtx, err := v2.ToUnstructuredTypedObject(nil, component.GetEffectiveRepositoryContext()) // decode the unstructured type into a specific type ociRepo := &v2.OCIRegistryRepository{} check(unstructuredRepoCtx.DecodeInto(ociRepo)) diff --git a/bindings-go/go.mod b/bindings-go/go.mod index b479d3a1..d9a091f2 100644 --- a/bindings-go/go.mod +++ b/bindings-go/go.mod @@ -6,6 +6,7 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v0.4.0 github.com/mandelsoft/vfs v0.0.0-20210530103237-5249dc39ce91 + github.com/modern-go/reflect2 v1.0.1 // indirect github.com/onsi/ginkgo v1.14.0 github.com/onsi/gomega v1.10.1 github.com/opencontainers/go-digest v1.0.0 diff --git a/bindings-go/oci/manifest.go b/bindings-go/oci/manifest.go index f04cc44a..eeeec5f2 100644 --- a/bindings-go/oci/manifest.go +++ b/bindings-go/oci/manifest.go @@ -41,8 +41,8 @@ type BlobStore interface { // ManifestBuilder converts a component descriptor with local defined blobs // into a oci component descriptor with blobs as layers of the component descriptor. type ManifestBuilder struct { - store BlobStore - archive *ctf.ComponentArchive + store BlobStore + archive *ctf.ComponentArchive componentDescriptorStorageType string } @@ -127,10 +127,10 @@ func (b *ManifestBuilder) addComponentDescriptorDesc() (ocispecv1.Descriptor, er var buf bytes.Buffer tw := tar.NewWriter(&buf) if err := tw.WriteHeader(&tar.Header{ - Typeflag: tar.TypeReg, - Name: ctf.ComponentDescriptorFileName, - Size: int64(len(data)), - ModTime: time.Now(), + Typeflag: tar.TypeReg, + Name: ctf.ComponentDescriptorFileName, + Size: int64(len(data)), + ModTime: time.Now(), }); err != nil { return ocispecv1.Descriptor{}, fmt.Errorf("unable to add component descriptor header: %w", err) } @@ -183,7 +183,7 @@ func (b *ManifestBuilder) addLocalBlobs(ctx context.Context) ([]ocispecv1.Descri if err != nil { return nil, fmt.Errorf("unable to convert ociBlob to untructured type: %w", err) } - res.Access = &unstructuredType + res.Access = unstructuredType b.archive.ComponentDescriptor.Resources[i] = res blobDescriptors = append(blobDescriptors, desc) } diff --git a/bindings-go/oci/oci_suite_test.go b/bindings-go/oci/oci_suite_test.go index d546c980..60caa1b5 100644 --- a/bindings-go/oci/oci_suite_test.go +++ b/bindings-go/oci/oci_suite_test.go @@ -22,7 +22,7 @@ func TestConfig(t *testing.T) { RunSpecs(t, "oci Test Suite") } -var _ = Describe("helper", func(){ +var _ = Describe("helper", func() { Context("OCIRef", func() { @@ -56,7 +56,7 @@ var _ = Describe("helper", func(){ It("should correctly parse a repository url with a sha256-digest name mapping", func() { repoCtx := cdv2.OCIRegistryRepository{ - BaseURL: "example.com:443", + BaseURL: "example.com:443", ComponentNameMapping: cdv2.OCIRegistryDigestMapping, } ref, err := oci.OCIRef(repoCtx, "somecomp", "v0.0.0") @@ -71,7 +71,7 @@ var _ = Describe("helper", func(){ // 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 + fetch func(ctx context.Context, ref string, desc ocispecv1.Descriptor, writer io.Writer) error } var _ oci.Client = &testClient{} @@ -86,7 +86,7 @@ func (t testClient) Fetch(ctx context.Context, ref string, desc ocispecv1.Descri // testCache describes a test resolve cache. type testCache struct { - get func (ctx context.Context, repoCtx cdv2.OCIRegistryRepository, name, version string) (*cdv2.ComponentDescriptor, error) + get func(ctx context.Context, repoCtx cdv2.OCIRegistryRepository, name, version string) (*cdv2.ComponentDescriptor, error) store func(ctx context.Context, descriptor *cdv2.ComponentDescriptor) error } @@ -99,4 +99,3 @@ func (t testCache) Get(ctx context.Context, repoCtx cdv2.OCIRegistryRepository, func (t testCache) Store(ctx context.Context, descriptor *cdv2.ComponentDescriptor) error { return t.store(ctx, descriptor) } - diff --git a/bindings-go/oci/resolve.go b/bindings-go/oci/resolve.go index d518e2df..1b728842 100644 --- a/bindings-go/oci/resolve.go +++ b/bindings-go/oci/resolve.go @@ -91,17 +91,17 @@ type Cache interface { // Resolver is a generic resolve to resolve a component descriptor from a oci registry. // This resolver implements the ctf.ComponentResolver interface. type Resolver struct { - log logr.Logger - client Client - cache Cache + log logr.Logger + client Client + cache Cache decodeOpts []codec.DecodeOption } // NewResolver creates a new resolver. func NewResolver(client Client, decodeOpts ...codec.DecodeOption) *Resolver { return &Resolver{ - log: logr.Discard(), - client: client, + log: logr.Discard(), + client: client, decodeOpts: decodeOpts, } } @@ -162,7 +162,7 @@ func (r *Resolver) resolve(ctx context.Context, repoCtx v2.Repository, name, ver } } else { if withBlobResolver { - manifest, ref , err := r.fetchManifest(ctx, repo, name, version) + manifest, ref, err := r.fetchManifest(ctx, repo, name, version) if err != nil { return nil, nil, err } @@ -172,7 +172,7 @@ func (r *Resolver) resolve(ctx context.Context, repoCtx v2.Repository, name, ver } } - manifest, ref , err := r.fetchManifest(ctx, repo, name, version) + manifest, ref, err := r.fetchManifest(ctx, repo, name, version) if err != nil { return nil, nil, err } diff --git a/bindings-go/oci/resolve_test.go b/bindings-go/oci/resolve_test.go index d5b08ab3..03a0a472 100644 --- a/bindings-go/oci/resolve_test.go +++ b/bindings-go/oci/resolve_test.go @@ -21,7 +21,7 @@ import ( "github.com/gardener/component-spec/bindings-go/oci" ) -var _ = Describe("resolve", func(){ +var _ = Describe("resolve", func() { Context("Resolve", func() { @@ -32,12 +32,12 @@ var _ = Describe("resolve", func(){ return &ocispecv1.Manifest{ Config: ocispecv1.Descriptor{ MediaType: oci.ComponentDescriptorConfigMimeType, - Digest: digest.FromString("config"), + Digest: digest.FromString("config"), }, Layers: []ocispecv1.Descriptor{ { MediaType: oci.ComponentDescriptorJSONMimeType, - Digest: digest.FromString("cd"), + Digest: digest.FromString("cd"), }, }, }, nil @@ -48,7 +48,7 @@ var _ = Describe("resolve", func(){ config := oci.ComponentDescriptorConfig{ ComponentDescriptorLayer: &oci.OciBlobRef{ MediaType: oci.ComponentDescriptorConfigMimeType, - Digest: digest.FromString("cd").String(), + Digest: digest.FromString("cd").String(), }, } return json.NewEncoder(writer).Encode(config) @@ -69,7 +69,7 @@ var _ = Describe("resolve", func(){ cd, err := oci.NewResolver(ociClient).Resolve(ctx, cdv2.NewOCIRegistryRepository("example.com", ""), "example.com/my-comp", "0.0.0") Expect(err).ToNot(HaveOccurred()) repoCtx := &cdv2.OCIRegistryRepository{} - Expect(cd.GetEffectiveRepositoryContext().DecodeInto(repoCtx)).To(Succeed()) + Expect(cdv2.DecodeInto(cd.GetEffectiveRepositoryContext(), repoCtx)).To(Succeed()) Expect(repoCtx.BaseURL).To(Equal("example.com"), "the repository context should be injected") }) @@ -116,12 +116,12 @@ var _ = Describe("resolve", func(){ return &ocispecv1.Manifest{ Config: ocispecv1.Descriptor{ MediaType: oci.ComponentDescriptorConfigMimeType, - Digest: digest.FromString("config"), + Digest: digest.FromString("config"), }, Layers: []ocispecv1.Descriptor{ { MediaType: oci.ComponentDescriptorJSONMimeType, - Digest: digest.FromString("cd"), + Digest: digest.FromString("cd"), }, }, }, nil @@ -132,7 +132,7 @@ var _ = Describe("resolve", func(){ config := oci.ComponentDescriptorConfig{ ComponentDescriptorLayer: &oci.OciBlobRef{ MediaType: oci.ComponentDescriptorConfigMimeType, - Digest: digest.FromString("cd").String(), + Digest: digest.FromString("cd").String(), }, } return json.NewEncoder(writer).Encode(config) @@ -154,7 +154,7 @@ var _ = Describe("resolve", func(){ Expect(err).ToNot(HaveOccurred()) repoCtx := &cdv2.OCIRegistryRepository{} - Expect(cd.GetEffectiveRepositoryContext().DecodeInto(repoCtx)).To(Succeed()) + Expect(cdv2.DecodeInto(cd.GetEffectiveRepositoryContext(), repoCtx)).To(Succeed()) Expect(repoCtx.BaseURL).To(Equal("example.com"), "the repository context should be injected") Expect(storeCalled).To(BeTrue(), "the cache store function should be called") }) diff --git a/bindings-go/utils/selector/selector.go b/bindings-go/utils/selector/selector.go index 93f104eb..c502d7a9 100644 --- a/bindings-go/utils/selector/selector.go +++ b/bindings-go/utils/selector/selector.go @@ -39,7 +39,7 @@ func (s SelectorFunc) Match(obj map[string]string) (bool, error) { // MatchSelectors checks whether all selectors matches the given obj. func MatchSelectors(obj map[string]string, selectors ...Interface) (bool, error) { for _, sel := range selectors { - ok, err:= sel.Match(obj) + ok, err := sel.Match(obj) if err != nil { return false, err } diff --git a/language-independent/component-descriptor-v2-schema.yaml b/language-independent/component-descriptor-v2-schema.yaml index af5482e1..984a59c1 100644 --- a/language-independent/component-descriptor-v2-schema.yaml +++ b/language-independent/component-descriptor-v2-schema.yaml @@ -352,7 +352,6 @@ definitions: - $ref: '#/definitions/ociRepositoryContext' # currently, we only allow this one provider: type: 'string' - enum: ['internal', 'external'] labels: type: 'array' items: