Skip to content

Commit

Permalink
feat: ocitar reader
Browse files Browse the repository at this point in the history
  • Loading branch information
morlay committed May 22, 2024
1 parent 6e1fa78 commit 9fe0b62
Show file tree
Hide file tree
Showing 13 changed files with 816 additions and 112 deletions.
59 changes: 24 additions & 35 deletions pkg/artifact/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package artifact
import (
"bytes"
"encoding/json"
"github.com/octohelm/crkit/pkg/ociutil"
"sync/atomic"

v1 "github.com/google/go-containerregistry/pkg/v1"
Expand All @@ -12,51 +13,46 @@ import (
specv1 "github.com/opencontainers/image-spec/specs-go/v1"
)

func Artifact(img v1.Image, c Config) (v1.Image, error) {
return &artifactImage{
func WithAnnotations(annotations map[string]string) Option {
return func(i *artifactImage) {
i.annotations = annotations
}
}

type Option = func(i *artifactImage)

func Artifact(img v1.Image, c Config, optFns ...Option) (v1.Image, error) {
i := &artifactImage{
Image: img,
config: c,
}, nil
}
}

type artifactImage struct {
v1.Image
config Config
for _, optFn := range optFns {
optFn(i)
}

m atomic.Pointer[specv1.Manifest]
return ociutil.FromRaw(i), nil
}

func (img *artifactImage) ArtifactType() (string, error) {
return img.config.ArtifactType()
type artifactImage struct {
v1.Image
config Config
annotations map[string]string
m atomic.Pointer[specv1.Manifest]
}

func (img *artifactImage) MediaType() (types.MediaType, error) {
return types.OCIManifestSchema1, nil
}

func (i *artifactImage) ConfigName() (v1.Hash, error) {
return partial.ConfigName(i)
func (img *artifactImage) ArtifactType() (string, error) {
return img.config.ArtifactType()
}

func (img *artifactImage) RawConfigFile() ([]byte, error) {
return img.config.RawConfigFile()
}

func (img *artifactImage) Manifest() (*v1.Manifest, error) {
raw, err := img.RawManifest()
if err != nil {
return nil, err
}

m := &v1.Manifest{}

if err := json.Unmarshal(raw, m); err != nil {
return nil, err
}

return m, nil
}

func (img *artifactImage) RawManifest() ([]byte, error) {
m, err := img.OCIManifest()
if err != nil {
Expand Down Expand Up @@ -103,6 +99,7 @@ func (img *artifactImage) OCIManifest() (*specv1.Manifest, error) {
Size: cfgSize,
Digest: digest.Digest(cfgHash.String()),
},
Annotations: img.annotations,
}
m.SchemaVersion = 2

Expand Down Expand Up @@ -142,11 +139,3 @@ func (img *artifactImage) OCIManifest() (*specv1.Manifest, error) {

return m, nil
}

func (img *artifactImage) Size() (int64, error) {
return partial.Size(img)
}

func (img *artifactImage) Digest() (v1.Hash, error) {
return partial.Digest(img)
}
170 changes: 170 additions & 0 deletions pkg/kubepkg/image_iter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package kubepkg

import (
"encoding/json"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
kubepkgv1alpha1 "github.com/octohelm/kubepkgspec/pkg/apis/kubepkg/v1alpha1"
specv1 "github.com/opencontainers/image-spec/specs-go/v1"
"iter"
)

func Push(i ImageIter, options ...remote.Option) error {
for ref, img := range i.Images() {
if err := remote.Put(ref, img, options...); err != nil {
return err
}
}
return i.Err()
}

func KubePkg(idx v1.ImageIndex) (*kubepkgv1alpha1.KubePkg, error) {
indexManifest, err := idx.IndexManifest()
if err != nil {
return nil, err
}

for _, m := range indexManifest.Manifests {
if m.ArtifactType == ArtifactType {
img, err := idx.Image(m.Digest)
if err != nil {
return nil, err
}

rawConfig, err := img.RawConfigFile()
if err != nil {
return nil, err
}
kpkg := &kubepkgv1alpha1.KubePkg{}
if err := json.Unmarshal(rawConfig, kpkg); err != nil {
return nil, err
}
return kpkg, nil
}
}

return nil, nil
}

func WithRenamer(renamer Renamer) ImageIterOption {
return func(i *imageIter) {
i.renamer = renamer
}
}

func WithRegistry(r Registry) ImageIterOption {
return func(i *imageIter) {
i.registry = r
}
}

type ImageIterOption func(i *imageIter)

func NewImageIter(idx v1.ImageIndex, options ...ImageIterOption) ImageIter {
i := &imageIter{
ImageIndex: idx,
}

for _, o := range options {
o(i)
}

return i
}

type ImageIter interface {
Images() iter.Seq2[name.Reference, remote.Taggable]
Err() error
}

type imageIter struct {
ImageIndex v1.ImageIndex

registry Registry
renamer Renamer

err error
}

func (r *imageIter) Err() error {
return r.err
}

func (r *imageIter) Done(err error) {
r.err = err
}

func (p *imageIter) Repository(repoName string) (name.Repository, error) {
if r := p.registry; r != nil {
return r.Repo(repoName), nil
}
return name.NewRepository(repoName)
}

func (r *imageIter) Images() iter.Seq2[name.Reference, remote.Taggable] {
indexManifest, err := r.ImageIndex.IndexManifest()
if err != nil {
r.Done(err)

return func(yield func(name.Reference, remote.Taggable) bool) {

}
}

return func(yield func(name.Reference, remote.Taggable) bool) {
for _, d := range indexManifest.Manifests {
if d.Annotations == nil {
continue
}

imageName := d.Annotations[specv1.AnnotationBaseImageName]
if imageName == "" {
continue
}

tag := d.Annotations[specv1.AnnotationRefName]
if tag == "" {
continue
}

repo, err := r.Repository(imageName)
if err != nil {
r.Done(err)
return
}

if r.renamer != nil {
renamed, err := r.Repository(r.renamer.Rename(repo))
if err != nil {
r.Done(err)
return
}
repo = renamed
}

ref := repo.Tag(tag)

if d.MediaType.IsImage() {
img, err := r.ImageIndex.Image(d.Digest)
if err != nil {
r.Done(err)
return
}

if !yield(ref, img) {
return
}
} else if d.MediaType.IsIndex() {
index, err := r.ImageIndex.ImageIndex(d.Digest)
if err != nil {
r.Done(err)
return
}
if !yield(ref, index) {
return
}
}
}
}
}
42 changes: 32 additions & 10 deletions pkg/kubepkg/packer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package kubepkg

import (
"context"
"fmt"
"github.com/octohelm/kubepkgspec/pkg/kubepkg"
"iter"
"sort"
Expand Down Expand Up @@ -29,9 +30,10 @@ const (
)

type Packer struct {
Registry Registry

CreatePuller func(repo name.Repository, options ...remote.Option) (*remote.Puller, error)
Cache cache.Cache
Registry *name.Registry
Platforms []string
Renamer Renamer

Expand Down Expand Up @@ -78,10 +80,6 @@ func (p *Packer) SupportedPlatforms(supportedPlatform []string) iter.Seq[v1.Plat

func (p *Packer) Repository(repoName string) (name.Repository, error) {
if registry := p.Registry; registry != nil {
registryName := registry.Name()
if strings.HasPrefix(repoName, registryName) {
return registry.Repo(repoName[len(registryName)+1:]), nil
}
return registry.Repo(repoName), nil
}
return name.NewRepository(repoName)
Expand Down Expand Up @@ -110,7 +108,20 @@ func (p *Packer) PackAsIndex(ctx context.Context, kpkg *kubepkgv1alpha1.KubePkg)

var finalIndex v1.ImageIndex = empty.Index

finalIndex, err = p.appendManifests(finalIndex, kubePkgImage, nil, nil)
namespace := kpkg.Namespace
if namespace == "" {
namespace = "default"
}

r, err := p.Repository(fmt.Sprintf("%s/artifact-kubepkg-%s", namespace, kpkg.Name))
if err != nil {
return nil, err
}

finalIndex, err = p.appendManifests(finalIndex, kubePkgImage, nil, &kubepkgv1alpha1.Image{
Name: p.ImageName(r),
Tag: kpkg.Spec.Version,
})
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -244,7 +255,9 @@ func (p *Packer) PackAsKubePkgImage(ctx context.Context, kpkg *kubepkgv1alpha1.K
}
}

return artifact.Artifact(kubepkgImage, &Config{KubePkg: kpkg})
return artifact.Artifact(kubepkgImage, &Config{KubePkg: kpkg}, artifact.WithAnnotations(map[string]string{
specv1.AnnotationRefName: kpkg.Spec.Version,
}))
}

func (p *Packer) appendArtifactLayer(kubepkgImage v1.Image, src v1.Image, d v1.Descriptor, img *kubepkgv1alpha1.Image) (v1.Image, error) {
Expand Down Expand Up @@ -296,9 +309,18 @@ func (p *Packer) appendManifests(idx v1.ImageIndex, source partial.Describable,
if add.Annotations == nil {
add.Annotations = map[string]string{}
}
add.Annotations[specv1.AnnotationBaseImageName] = image.Name
add.Annotations[specv1.AnnotationRefName] = image.Tag
add.Annotations[images.AnnotationImageName] = image.FullName()

if image.Name != "" {
add.Annotations[specv1.AnnotationBaseImageName] = image.Name

if add.ArtifactType == "" {
add.Annotations[images.AnnotationImageName] = image.FullName()
}
}

if image.Tag != "" {
add.Annotations[specv1.AnnotationRefName] = image.Tag
}
}

return mutate.AppendManifests(idx, add), nil
Expand Down
Loading

0 comments on commit 9fe0b62

Please sign in to comment.