Skip to content

Commit

Permalink
Structure Build config a little
Browse files Browse the repository at this point in the history
  • Loading branch information
dskiff committed Apr 25, 2024
1 parent 8037130 commit e6b3f27
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 74 deletions.
40 changes: 20 additions & 20 deletions pkg/build/base.go
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
package build

import (
"context"
"fmt"
"log"

"github.com/google/go-containerregistry/pkg/authn"
"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/remote"
)

func GetBaseImage(ctx context.Context, baseName string, cfg RunConfig) (v1.Image, error) {
if baseName == "scratch" {
func GetBaseImage(ctx RunCtx, baseRef string, platform Platform, keychain authn.Keychain) (v1.Image, error) {
if baseRef == "scratch" {
return empty.Image, nil
}

baseRef, baseIndex, err := fetchImageIndex(ctx, baseName, cfg)
ref, index, err := fetchImageIndex(ctx, baseRef, keychain)
if err != nil {
return nil, fmt.Errorf("failed to retrieve base image index: %w", err)
}
baseDigest, err := baseIndex.Digest()
baseDigest, err := index.Digest()
if err != nil {
return nil, fmt.Errorf("failed to retrieve base image digest: %w", err)
}
log.Println("Using base image:", baseRef.Name()+"@"+baseDigest.String())
log.Println("Using base image:", ref.Name()+"@"+baseDigest.String())

return getImageForPlatform(baseIndex, cfg.PlatformArch, cfg.PlatformOs)
return getImageForPlatform(index, platform)
}

func fetchImageIndex(ctx context.Context, src string, cfg RunConfig) (name.Reference, v1.ImageIndex, error) {
func fetchImageIndex(ctx RunCtx, src string, keychain authn.Keychain) (name.Reference, v1.ImageIndex, error) {
ref, err := name.ParseReference(src)
if err != nil {
return nil, nil, err
}
base, err := remote.Index(ref, remote.WithContext(ctx), remote.WithAuthFromKeychain(cfg.RemoteKeychain))
base, err := remote.Index(ref, remote.WithContext(ctx.Ctx), remote.WithAuthFromKeychain(keychain))
return ref, base, err
}

func getDigestForPlatform(index v1.ImageIndex, arch string, os string) (v1.Hash, error) {
func getImageForPlatform(index v1.ImageIndex, platform Platform) (v1.Image, error) {
digest, err := getDigestForPlatform(index, platform)
if err != nil {
return nil, err
}
return index.Image(digest)
}

func getDigestForPlatform(index v1.ImageIndex, platform Platform) (v1.Hash, error) {
manifest, err := index.IndexManifest()
if err != nil {
return v1.Hash{}, err
}

// Find the manifest for the platform
for _, m := range manifest.Manifests {
if m.Platform.Architecture == arch && m.Platform.OS == os {
if m.Platform.Architecture == platform.Arch && m.Platform.OS == platform.OS {
return m.Digest, nil
}
}

return v1.Hash{}, fmt.Errorf("no manifest found for platform %s/%s", arch, os)
}

func getImageForPlatform(index v1.ImageIndex, arch string, os string) (v1.Image, error) {
digest, err := getDigestForPlatform(index, arch, os)
if err != nil {
return nil, err
}
return index.Image(digest)
return v1.Hash{}, fmt.Errorf("no manifest found for platform %s", platform)
}
8 changes: 4 additions & 4 deletions pkg/build/layers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ import (
"github.com/google/go-containerregistry/pkg/v1/tarball"
)

func createLayerFromFolder(srcPath, dstPath string, cfg RunConfig, opts ...tarball.LayerOption) (v1.Layer, error) {
tarPath, err := createTarFromFolder(srcPath, dstPath, cfg)
func createLayerFromFolder(ctx RunCtx, srcPath, dstPath string, opts ...tarball.LayerOption) (v1.Layer, error) {
tarPath, err := createTarFromFolder(ctx, srcPath, dstPath)
if err != nil {
return nil, err
}

return tarball.LayerFromFile(tarPath, opts...)
}

func createTarFromFolder(srcPath, dstPath string, cfg RunConfig) (string, error) {
tarFile, err := CreateTempFile(cfg)
func createTarFromFolder(ctx RunCtx, srcPath, dstPath string) (string, error) {
tarFile, err := CreateTempFile(ctx)
if err != nil {
return "", err
}
Expand Down
13 changes: 6 additions & 7 deletions pkg/build/publish.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package build

import (
"context"
"fmt"
"log"

Expand All @@ -11,31 +10,31 @@ import (
"github.com/google/go-containerregistry/pkg/v1/remote"
)

func Publish(ctx context.Context, tag name.Tag, image v1.Image, cfg RunConfig) error {
func Publish(ctx RunCtx, tag name.Tag, image v1.Image, target RunConfigTarget) error {
digest, err := image.Digest()
if err != nil {
return fmt.Errorf("failed to retrieve new image digest: %w", err)
}

log.Printf("Publishing %s...", tag.Name()+"@"+digest.String())

switch cfg.TargetType {
switch target.Type {
case REMOTE:
log.Println("Publishing to remote...")

err := remote.Write(tag, image, remote.WithContext(ctx),
remote.WithAuthFromKeychain(cfg.RemoteKeychain))
err := remote.Write(tag, image, remote.WithContext(ctx.Ctx),
remote.WithAuthFromKeychain(ctx.Keychain))
if err != nil {
return fmt.Errorf("failed to write image to remote: %w", err)
}
case LOCAL_DAEMON:
log.Println("Publishing to local daemon...")
_, err := daemon.Write(tag, image, daemon.WithContext(ctx))
_, err := daemon.Write(tag, image, daemon.WithContext(ctx.Ctx))
if err != nil {
return fmt.Errorf("failed to write image to daemon: %w", err)
}
default:
return fmt.Errorf("unknown target type: %d", cfg.TargetType)
return fmt.Errorf("unknown target type: %d", target.Type)
}

return nil
Expand Down
59 changes: 41 additions & 18 deletions pkg/build/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,58 @@ const (
LOCAL_DAEMON
)

type RunConfig struct {
SrcPath string
DstPath string
Entrypoint string
type Platform struct {
OS string
Arch string
}

BaseImage string
TargetRepo string
TargetType TargetType
RemoteKeychain authn.Keychain
func (p Platform) String() string {
return p.OS + "/" + p.Arch
}

PlatformOs string
PlatformArch string
type RunConfigBase struct {
SourceUrl string
}

type RunConfigInjectLayer struct {
Platform Platform

SourcePath string
DestinationPath string
Entrypoint string
}

TempPath string
type RunConfigTarget struct {
Repo string
Type TargetType
}

type RunConfig struct {
BaseRef string
InjectLayer RunConfigInjectLayer
Target RunConfigTarget
}

type RunCtx struct {
Ctx context.Context
ExitCleanupWatcher *ExitCleanupWatcher
Keychain authn.Keychain

TempPath string
}

func Run(ctx context.Context, cfg RunConfig) error {
tag, err := name.NewTag(cfg.TargetRepo)
func Build(ctx RunCtx, cfg RunConfig) error {
tag, err := name.NewTag(cfg.Target.Repo)
if err != nil {
return fmt.Errorf("failed to parse target repo: %w", err)
}

baseImage, err := GetBaseImage(ctx, cfg.BaseImage, cfg)
baseImage, err := GetBaseImage(ctx, cfg.BaseRef, cfg.InjectLayer.Platform, ctx.Keychain)
if err != nil {
return fmt.Errorf("failed to retrieve base image: %w", err)
}

newLayer, err := createLayerFromFolder(cfg.SrcPath, cfg.DstPath, cfg)
newLayer, err := createLayerFromFolder(ctx, cfg.InjectLayer.SourcePath, cfg.InjectLayer.DestinationPath)
if err != nil {
return fmt.Errorf("failed to create layer from source: %w", err)
}
Expand All @@ -60,7 +83,7 @@ func Run(ctx context.Context, cfg RunConfig) error {
return fmt.Errorf("failed to mutate config: %w", err)
}

return Publish(ctx, tag, newImage, cfg)
return Publish(ctx, tag, newImage, cfg.Target)
}

func mutateConfig(img v1.Image, runCfg RunConfig) (v1.Image, error) {
Expand All @@ -70,9 +93,9 @@ func mutateConfig(img v1.Image, runCfg RunConfig) (v1.Image, error) {
}
cfg = cfg.DeepCopy()

cfg.Config.Entrypoint = []string{runCfg.Entrypoint}
cfg.Config.WorkingDir = runCfg.InjectLayer.DestinationPath
cfg.Config.Entrypoint = []string{runCfg.InjectLayer.Entrypoint}
cfg.Config.Cmd = nil
cfg.Config.WorkingDir = runCfg.DstPath

return mutate.ConfigFile(img, cfg)
}
6 changes: 3 additions & 3 deletions pkg/build/temp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
"os"
)

func CreateTempFile(cfg RunConfig) (*os.File, error) {
fp, err := os.CreateTemp(cfg.TempPath, "tko-temp-*.tar")
func CreateTempFile(ctx RunCtx) (*os.File, error) {
fp, err := os.CreateTemp(ctx.TempPath, "tko-temp-*.tar")
if err != nil {
return nil, err
}
cfg.ExitCleanupWatcher.Append(fp.Name())
ctx.ExitCleanupWatcher.Append(fp.Name())
return fp, nil
}
50 changes: 28 additions & 22 deletions pkg/cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,36 @@ func (b *BuildCmd) Run(cliCtx *CliCtx) error {
)

cfg := build.RunConfig{
SrcPath: b.SourcePath,
DstPath: os.Getenv("TKO_DEST_PATH"),
Entrypoint: os.Getenv("TKO_ENTRYPOINT"),

BaseImage: os.Getenv("TKO_BASE_IMAGE"),
TargetRepo: os.Getenv("TKO_TARGET_REPO"),
TargetType: targetType,
RemoteKeychain: keychain,

PlatformOs: "linux",
PlatformArch: "amd64",

TempPath: os.Getenv("TKO_TEMP_PATH"),
ExitCleanupWatcher: cliCtx.ExitCleanWatcher,
BaseRef: os.Getenv("TKO_BASE_IMAGE"),
InjectLayer: build.RunConfigInjectLayer{
Platform: build.Platform{
OS: "linux",
Arch: "amd64",
},
SourcePath: b.SourcePath,
DestinationPath: os.Getenv("TKO_DEST_PATH"),
Entrypoint: os.Getenv("TKO_ENTRYPOINT"),
},
Target: build.RunConfigTarget{
Repo: os.Getenv("TKO_TARGET_REPO"),
Type: targetType,
},
}

if cfg.BaseImage == "" {
cfg.BaseImage = "cgr.dev/chainguard/static:latest"
if cfg.BaseRef == "" {
cfg.BaseRef = "cgr.dev/chainguard/static:latest"
}

if cfg.TargetRepo == "" {
if cfg.Target.Repo == "" {
return fmt.Errorf("target repo must be set")
}

if cfg.DstPath == "" {
cfg.DstPath = "/tko-app"
if cfg.InjectLayer.DestinationPath == "" {
cfg.InjectLayer.DestinationPath = "/tko-app"
}

if cfg.Entrypoint == "" {
cfg.Entrypoint = "/tko-app/app"
if cfg.InjectLayer.Entrypoint == "" {
cfg.InjectLayer.Entrypoint = "/tko-app/app"
}

out, err := yaml.Marshal(cfg)
Expand All @@ -80,7 +80,13 @@ func (b *BuildCmd) Run(cliCtx *CliCtx) error {
logs.Debug.SetOutput(os.Stderr)
}

return build.Run(cliCtx.Ctx, cfg)
return build.Build(build.RunCtx{
Ctx: cliCtx.Ctx,
ExitCleanupWatcher: cliCtx.ExitCleanWatcher,
Keychain: keychain,

TempPath: os.Getenv("TKO_TEMP_PATH"),
}, cfg)
}

func parseTargetType(str string) (build.TargetType, error) {
Expand Down

0 comments on commit e6b3f27

Please sign in to comment.