-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extended Tour Documentation #614
Changes from 9 commits
1cd4948
6c21f6f
62254fd
a09b014
6373f7a
3aad051
86c4859
b6de06a
0d298db
3bd9f0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,13 +1,270 @@ | ||||||
<!-- DO NOT MODIFY --> | ||||||
<!-- this file is generated by mdref --> | ||||||
<!-- from ../docsrc/01-getting-started/README.md --> | ||||||
# Basic Usage of OCM Repositories | ||||||
|
||||||
This [tour](example.go) illustrates the basic usage of the API to | ||||||
access component versions in an OCM repository. | ||||||
|
||||||
## Running the example | ||||||
|
||||||
You can just call the main program with some config file argument | ||||||
with the following content: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
|
||||||
```yaml | ||||||
component: github.com/mandelsoft/examples/cred1 | ||||||
repository: ghcr.io/mandelsoft/ocm | ||||||
version: 0.1.0 | ||||||
``` | ||||||
``` | ||||||
|
||||||
## Walkthrough | ||||||
|
||||||
The basic entry point for using the OCM library is always | ||||||
an [OCM Context object](../../contexts.md). It bundles all | ||||||
configuration settings and type registrations, like | ||||||
access methods, repository types, etc, and | ||||||
configuration settings, like credentials, | ||||||
which should be used when working with the OCM | ||||||
ecosystem. | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Therefore relates to the paragraph before, therefore I think it should be ok. |
||||||
Therefore, the first step is always to get access to such | ||||||
a context object. Our example uses the default context | ||||||
provided by the library, which covers the complete | ||||||
type registration contained in the executable. | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
It can be accessed by a function of the ocm package. | ||||||
|
||||||
```go | ||||||
ctx := ocm.DefaultContext() | ||||||
``` | ||||||
|
||||||
The context acts as the central entry | ||||||
point to get access to OCM elements. | ||||||
First, we get a repository, to look for | ||||||
component versions. We use the OCM | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
repository providing the standard OCM | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
components hosted on `ghcr.io`. | ||||||
|
||||||
For every storage technology used to store | ||||||
OCM components, there is a serializable | ||||||
descriptor object, the *repository specification*. | ||||||
It describes the information required to access | ||||||
the repository and can be used to store the serialized | ||||||
form as part of other resources, for example | ||||||
Kubernetes resources or configuration settings. | ||||||
The available repository implementations can be found | ||||||
under `.../pkg/contexts/ocm/repositories`. | ||||||
|
||||||
```go | ||||||
spec := ocireg.NewRepositorySpec("ghcr.io/open-component-model/ocm") | ||||||
``` | ||||||
|
||||||
The context can now be used to map the descriptor | ||||||
into a repository object, which then provides access | ||||||
to the OCM elements stored in this repository. | ||||||
|
||||||
```go | ||||||
repo, err := ctx.RepositoryForSpec(spec) | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "cannot setup repository") | ||||||
} | ||||||
``` | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
Many objects must be closed, if they should not be used | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. many objects must be closed, if they should not be used anymore. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
anymore, to release potentially allocated temporary resources. | ||||||
This is typically done by a `defer` statement placed after a | ||||||
successful object retrieval. | ||||||
|
||||||
```go | ||||||
defer repo.Close() | ||||||
``` | ||||||
|
||||||
Now we look for the versions of the component | ||||||
available in this repository. | ||||||
|
||||||
```go | ||||||
versions, err := c.ListVersions() | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "cannot query version names") | ||||||
} | ||||||
``` | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
OCM version names must follow the semver rules. | ||||||
Therefore, we can simply order the versions and print them. | ||||||
|
||||||
```go | ||||||
err = semverutils.SortVersions(versions) | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "cannot sort versions") | ||||||
} | ||||||
fmt.Printf("versions for component ocm.software/ocmcli: %s\n", strings.Join(versions, ", ")) | ||||||
``` | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
Now, we have a look at the latest version, it is | ||||||
the last one in the list. | ||||||
|
||||||
```go | ||||||
cv, err := c.LookupVersion(versions[len(versions)-1]) | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "cannot get latest version") | ||||||
} | ||||||
defer cv.Close() | ||||||
``` | ||||||
|
||||||
<a id="describe-version"></a> | ||||||
|
||||||
The component version object provides access | ||||||
to the component descriptor | ||||||
|
||||||
```go | ||||||
cd := cv.GetDescriptor() | ||||||
fmt.Printf("resources of the latest version:\n") | ||||||
fmt.Printf(" version: %s\n", cv.GetVersion()) | ||||||
fmt.Printf(" provider: %s\n", cd.Provider.Name) | ||||||
``` | ||||||
|
||||||
and the resources described by the component version. | ||||||
|
||||||
```go | ||||||
for i, r := range cv.GetResources() { | ||||||
fmt.Printf(" %2d: name: %s\n", i+1, r.Meta().GetName()) | ||||||
fmt.Printf(" extra identity: %s\n", r.Meta().GetExtraIdentity()) | ||||||
fmt.Printf(" resource type: %s\n", r.Meta().GetType()) | ||||||
acc, err := r.Access() | ||||||
if err != nil { | ||||||
fmt.Printf(" access: error: %s\n", err) | ||||||
} else { | ||||||
fmt.Printf(" access: %s\n", acc.Describe(ctx)) | ||||||
} | ||||||
} | ||||||
``` | ||||||
|
||||||
This results in the following output (the shown version might | ||||||
differ, because the code always describes the latest version): | ||||||
|
||||||
``` | ||||||
resources of the latest version: | ||||||
version: 0.6.0 | ||||||
provider: ocm.software | ||||||
1: name: ocmcli | ||||||
extra identity: "architecture"="amd64","os"="linux" | ||||||
resource type: executable | ||||||
access: Local blob sha256:6672528b57fd77cefa4c5a3395431b6a5aa14dc3ddad3ffe52343a7a518c2cd3[] | ||||||
2: name: ocmcli | ||||||
extra identity: "architecture"="arm64","os"="linux" | ||||||
resource type: executable | ||||||
access: Local blob sha256:9088cb8bbef1593b905d6bd3af6652165ff82cebd0d86540a7be9637324d036b[] | ||||||
3: name: ocmcli-image | ||||||
extra identity: | ||||||
resource type: ociImage | ||||||
access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.6.0 | ||||||
``` | ||||||
|
||||||
Resources have some metadata, like the resource identity and a resource type. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And relates to the sentence before |
||||||
And they describe how the content of the resource (as blob) can be accessed. | ||||||
This is done by an *access specification*, again a serializable descriptor, | ||||||
like the respository specification. | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sollte man hier nicht eventuell das "component version" als resource in Hochticks stellen oder noch so etwas wie "die Resource" oder "der Typ" oder was component version hier auch immer ist? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are more errors, here, fo example, the identity is not stored as label. I've reformulated the paragraph. |
||||||
The component version contains the executables for the OCM CLI | ||||||
for various platforms. The next step is to | ||||||
get the executable for the actual environment. | ||||||
The identity of a resource described by a component version | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
consists of a set of properties. The property name must | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
always be given. | ||||||
|
||||||
A convention is to use dedicated labels to indicate the operating system | ||||||
and the architecture for executables. | ||||||
|
||||||
```go | ||||||
id := metav1.NewIdentity("ocmcli", | ||||||
extraid.ExecutableOperatingSystem, runtime.GOOS, | ||||||
extraid.ExecutableArchitecture, runtime.GOARCH, | ||||||
) | ||||||
|
||||||
res, err := cv.GetResource(id) | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "resource %s", id) | ||||||
} | ||||||
``` | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reformulated |
||||||
Now we want to retrieve the executable. There are two basic ways | ||||||
to do this. | ||||||
|
||||||
First, there is the direct way to gain access to the blob by using | ||||||
the basic model operations to get a reader for the resource blob. | ||||||
Therefore, in a first step we get the access method for the resource | ||||||
|
||||||
```go | ||||||
var m ocm.AccessMethod | ||||||
m, err = res.AccessMethod() | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "cannot get access method") | ||||||
} | ||||||
defer m.Close() | ||||||
``` | ||||||
|
||||||
The method needs to be closed, because the method | ||||||
object may cache the technical blob representation | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. by accessing |
||||||
generated accessing the underlying access technology. | ||||||
(for example, accessing an OCI image requires a sequence of | ||||||
backend accesses for the manifest, the layers, etc which will | ||||||
then be packaged into a tar archive returned as blob). | ||||||
This caching may not be required, if the backend directly | ||||||
returns a blob. | ||||||
|
||||||
Now we get access to the reader providing the blob content. | ||||||
The blob features a mime type, which can be used to understand | ||||||
the format of the blob. Here, we have a plain octet stream. | ||||||
|
||||||
```go | ||||||
fmt.Printf(" found blob with mime type %s\n", m.MimeType()) | ||||||
reader, err = m.Reader() | ||||||
``` | ||||||
|
||||||
Because this sequence is a common operation, there is a | ||||||
utility function handling this sequence. A shorter way to get | ||||||
a resource reader is as follows: | ||||||
|
||||||
```go | ||||||
reader, err = utils.GetResourceReader(res) | ||||||
``` | ||||||
|
||||||
Before we download the content we check the error and prepare | ||||||
closing the reader, again | ||||||
|
||||||
```go | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "cannot get resource reader") | ||||||
} | ||||||
defer reader.Close() | ||||||
``` | ||||||
|
||||||
Now, we just read the content and copy it to the intended | ||||||
output file. | ||||||
|
||||||
```go | ||||||
file, err := os.OpenFile("/tmp/ocmcli", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0766) | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "cannot open output file") | ||||||
} | ||||||
defer file.Close() | ||||||
|
||||||
n, err := io.Copy(file, reader) | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "write executable") | ||||||
} | ||||||
fmt.Printf("%d bytes written\n", n) | ||||||
``` | ||||||
|
||||||
Another way to download a resource is to use registered downloaders. | ||||||
`download.DownloadResource` is used to download resources with specific handlers for the | ||||||
selected resource and mime type combinations. | ||||||
The executable downloader is registered by default and automatically | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
sets the X flag. | ||||||
|
||||||
```go | ||||||
_, err = download.DownloadResource(ctx, res, "/tmp/ocmcli", download.WithPrinter(common.NewPrinter(os.Stdout))) | ||||||
if err != nil { | ||||||
return errors.Wrapf(err, "download failed") | ||||||
} | ||||||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done