Skip to content

Commit

Permalink
use v1.Layers (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshrwolf authored Jan 27, 2025
1 parent 2a0e9f3 commit 13d8469
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 65 deletions.
6 changes: 4 additions & 2 deletions internal/bundler/apko.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (
apko_types "chainguard.dev/apko/pkg/build/types"
"chainguard.dev/apko/pkg/tarfs"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/remote"
)

Expand Down Expand Up @@ -78,7 +80,7 @@ func NewApko(opts ...ApkoOpt) (Bundler, error) {
return a, nil
}

func (a *apko) Bundle(ctx context.Context, repo name.Repository, layers ...Layerer) (name.Reference, error) {
func (a *apko) Bundle(ctx context.Context, repo name.Repository, layers ...v1.Layer) (name.Reference, error) {
bopts := []apko_build.Option{
apko_build.WithImageConfiguration(a.apkoConfig),
apko_build.WithArch(a.arch),
Expand All @@ -105,7 +107,7 @@ func (a *apko) Bundle(ctx context.Context, repo name.Repository, layers ...Layer
return nil, fmt.Errorf("failed to build image: %w", err)
}

img, err := appendLayers(base, layers...)
img, err := mutate.AppendLayers(base, layers...)
if err != nil {
return nil, fmt.Errorf("failed to append layers: %w", err)
}
Expand Down
50 changes: 33 additions & 17 deletions internal/bundler/append.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ import (

type AppendOpts struct {
RemoteOptions []remote.Option
Layers []Layerer
Layers []v1.Layer
Envs map[string]string
Cmd string
Entrypoint []string
}

func Append(ctx context.Context, source name.Reference, target name.Repository, opts AppendOpts) (name.Reference, error) {
desc, err := remote.Get(source, opts.RemoteOptions...)
// Append mutates the source Image or ImageIndex with the provided append
// options, and pushes it to the target repository via its digest.
func Append(ctx context.Context, base name.Reference, target name.Repository, opts AppendOpts) (name.Reference, error) {
desc, err := remote.Get(base, opts.RemoteOptions...)
if err != nil {
return nil, fmt.Errorf("failed to get image: %w", err)
}
Expand All @@ -42,12 +46,7 @@ func Append(ctx context.Context, source name.Reference, target name.Repository,
return nil, fmt.Errorf("failed to load image: %w", err)
}

mutated, err := appendLayers(baseimg, opts.Layers...)
if err != nil {
return nil, err
}

mutated, err = mutateConfig(mutated, opts.Envs)
mutated, err := appendToImage(ctx, baseimg, opts)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -86,17 +85,12 @@ func Append(ctx context.Context, source name.Reference, target name.Repository,
return ref, nil

} else if desc.MediaType.IsImage() {
baseimg, err := remote.Image(source, opts.RemoteOptions...)
baseimg, err := remote.Image(base, opts.RemoteOptions...)
if err != nil {
return nil, fmt.Errorf("failed to get image: %w", err)
}

mutated, err := appendLayers(baseimg, opts.Layers...)
if err != nil {
return nil, err
}

mutated, err = mutateConfig(mutated, opts.Envs)
mutated, err := appendToImage(ctx, baseimg, opts)
if err != nil {
return nil, err
}
Expand All @@ -117,7 +111,21 @@ func Append(ctx context.Context, source name.Reference, target name.Repository,
return nil, fmt.Errorf("unsupported media type: %s", desc.MediaType)
}

func mutateConfig(img v1.Image, envs map[string]string) (v1.Image, error) {
func appendToImage(_ context.Context, img v1.Image, opts AppendOpts) (v1.Image, error) {
mutated, err := mutate.AppendLayers(img, opts.Layers...)
if err != nil {
return nil, err
}

mutated, err = mutateConfig(mutated, opts.Envs, opts.Entrypoint, opts.Cmd)
if err != nil {
return nil, err
}

return mutated, nil
}

func mutateConfig(img v1.Image, envs map[string]string, entrypoint []string, cmd string) (v1.Image, error) {
cfg, err := img.ConfigFile()
if err != nil {
return nil, fmt.Errorf("failed to get config file: %w", err)
Expand All @@ -127,5 +135,13 @@ func mutateConfig(img v1.Image, envs map[string]string) (v1.Image, error) {
cfg.Config.Env = append(cfg.Config.Env, fmt.Sprintf("%s=%s", k, v))
}

if cmd != "" {
cfg.Config.Cmd = []string{cmd}
}

if len(entrypoint) > 0 {
cfg.Config.Entrypoint = entrypoint
}

return mutate.ConfigFile(img, cfg)
}
3 changes: 2 additions & 1 deletion internal/bundler/appender.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"

"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
)

Expand All @@ -30,7 +31,7 @@ func NewAppender(base name.Reference, opts ...AppenderOpt) (Bundler, error) {
return a, nil
}

func (a *appender) Bundle(ctx context.Context, repo name.Repository, layers ...Layerer) (name.Reference, error) {
func (a *appender) Bundle(ctx context.Context, repo name.Repository, layers ...v1.Layer) (name.Reference, error) {
opts := AppendOpts{
RemoteOptions: a.ropts,
Layers: layers,
Expand Down
3 changes: 2 additions & 1 deletion internal/bundler/bundler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import (
"context"

"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
)

type Bundler interface {
Bundle(ctx context.Context, repo name.Repository, layers ...Layerer) (name.Reference, error)
Bundle(ctx context.Context, repo name.Repository, layers ...v1.Layer) (name.Reference, error)
}
64 changes: 28 additions & 36 deletions internal/bundler/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,16 @@ import (
"archive/tar"
"io"
"io/fs"
"path/filepath"
"os"
"path"

"chainguard.dev/apko/pkg/tarfs"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/tarball"
)

type Layerer interface {
Layer() (v1.Layer, error)
}

var _ Layerer = &fsl{}

type fsl struct {
source fs.FS
target string
}

func NewFSLayer(source fs.FS, target string) Layerer {
return &fsl{
source: source,
target: target,
}
}

func (l *fsl) Layer() (v1.Layer, error) {
// NewLayerFromFS creates a v1.Layer from a filesystem and target path.
func NewLayerFromFS(source fs.FS, target string) (v1.Layer, error) {
return tarball.LayerFromOpener(func() (io.ReadCloser, error) {
pr, pw := io.Pipe()

Expand All @@ -38,7 +22,7 @@ func (l *fsl) Layer() (v1.Layer, error) {
defer tw.Close()
defer pw.Close()

if err := fs.WalkDir(l.source, ".", func(path string, d fs.DirEntry, err error) error {
if err := fs.WalkDir(source, ".", func(p string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
Expand All @@ -53,14 +37,14 @@ func (l *fsl) Layer() (v1.Layer, error) {
return err
}

hdr.Name = filepath.Join(l.target, path)
hdr.Name = path.Join(target, p)

if err := tw.WriteHeader(hdr); err != nil {
return err
}

if !d.IsDir() {
f, err := l.source.Open(path)
f, err := source.Open(p)
if err != nil {
return err
}
Expand All @@ -82,19 +66,27 @@ func (l *fsl) Layer() (v1.Layer, error) {
})
}

func appendLayers(img v1.Image, layers ...Layerer) (v1.Image, error) {
mutated := img
// NewLayerFromPath creates a v1.Layer from a local path.
func NewLayerFromPath(source string, target string) (v1.Layer, error) {
pi, err := os.Stat(source)
if err != nil {
return nil, err
}

if pi.IsDir() {
return NewLayerFromFS(os.DirFS(source), target)
}

for _, l := range layers {
layer, err := l.Layer()
if err != nil {
return nil, err
}
// Handle single file
data, err := os.ReadFile(source)
if err != nil {
return nil, err
}

mutated, err = mutate.AppendLayers(mutated, layer)
if err != nil {
return nil, err
}
tfs := tarfs.New()
if err := tfs.WriteFile(pi.Name(), data, pi.Mode()); err != nil {
return nil, err
}
return mutated, nil

return NewLayerFromFS(tfs, target)
}
11 changes: 8 additions & 3 deletions internal/provider/harness_docker_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/chainguard-dev/terraform-provider-imagetest/internal/provider/framework"
"github.com/docker/docker/api/types/mount"
"github.com/google/go-containerregistry/pkg/name"
ggcrv1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
Expand Down Expand Up @@ -210,12 +211,16 @@ func (r *HarnessDockerResource) harness(ctx context.Context, data *HarnessDocker
return nil, []diag.Diagnostic{diag.NewErrorDiagnostic("failed to create bundler", err.Error())}
}

var layers []bundler.Layerer
var layers []ggcrv1.Layer
for _, sl := range data.Layers {
layers = append(layers, bundler.NewFSLayer(
layer, err := bundler.NewLayerFromFS(
os.DirFS(sl.Source.ValueString()),
sl.Target.ValueString(),
))
)
if err != nil {
return nil, []diag.Diagnostic{diag.NewErrorDiagnostic("failed to create layer", err.Error())}
}
layers = append(layers, layer)
}

bref, err := b.Bundle(ctx, r.store.repo, layers...)
Expand Down
12 changes: 7 additions & 5 deletions internal/provider/harness_k3s_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/chainguard-dev/terraform-provider-imagetest/internal/provider/framework"
"github.com/docker/docker/api/types/mount"
"github.com/google/go-containerregistry/pkg/name"
ggcrv1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
Expand Down Expand Up @@ -167,16 +168,17 @@ func (r *HarnessK3sResource) harness(ctx context.Context, data *HarnessK3sResour
return nil, []diag.Diagnostic{diag.NewErrorDiagnostic("failed to create bundler", err.Error())}
}

var ls []bundler.Layerer
var ls []ggcrv1.Layer

if sandbox := data.Sandbox; sandbox != nil {
log.Info(ctx, "parsing sandbox", "raw", sandbox)

for _, l := range sandbox.Layers {
ls = append(ls, bundler.NewFSLayer(
os.DirFS(l.Source.ValueString()),
l.Target.ValueString(),
))
layer, err := bundler.NewLayerFromPath(l.Source.ValueString(), l.Target.ValueString())
if err != nil {
return nil, []diag.Diagnostic{diag.NewErrorDiagnostic("failed to create layer", err.Error())}
}
ls = append(ls, layer)
}

for _, m := range sandbox.Mounts {
Expand Down

0 comments on commit 13d8469

Please sign in to comment.