Skip to content

chore(internal/provider): refactor cached_image_resource #46

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

Merged
merged 9 commits into from
Sep 4, 2024
103 changes: 103 additions & 0 deletions internal/imgutil/imgutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package imgutil

import (
"archive/tar"
"context"
"fmt"
"io"
"os"
"path/filepath"

"github.com/coder/envbuilder/constants"
"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/remote"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

// GetRemoteImage fetches the image manifest of the image.
func GetRemoteImage(imgRef string) (v1.Image, error) {
ref, err := name.ParseReference(imgRef)
if err != nil {
return nil, fmt.Errorf("parse reference: %w", err)
}

img, err := remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil {
return nil, fmt.Errorf("check remote image: %w", err)
}

return img, nil
}

// ExtractEnvbuilderFromImage reads the image located at imgRef and extracts
// MagicBinaryLocation to destPath.
func ExtractEnvbuilderFromImage(ctx context.Context, imgRef, destPath string) error {
needle := filepath.Clean(constants.MagicBinaryLocation)[1:] // skip leading '/'
img, err := GetRemoteImage(imgRef)
if err != nil {
return fmt.Errorf("check remote image: %w", err)
}

layers, err := img.Layers()
if err != nil {
return fmt.Errorf("get image layers: %w", err)
}

// Check the layers in reverse order. The last layers are more likely to
// include the binary.
for i := len(layers) - 1; i >= 0; i-- {
ul, err := layers[i].Uncompressed()
if err != nil {
return fmt.Errorf("get uncompressed layer: %w", err)
}

tr := tar.NewReader(ul)
for {
th, err := tr.Next()
if err == io.EOF {
break
}

if err != nil {
return fmt.Errorf("read tar header: %w", err)
}

name := filepath.Clean(th.Name)
if th.Typeflag != tar.TypeReg {
tflog.Debug(ctx, "skip non-regular file", map[string]any{"name": name, "layer_idx": i + 1})
continue
}

if name != needle {
tflog.Debug(ctx, "skip file", map[string]any{"name": name, "layer_idx": i + 1})
continue
}

tflog.Debug(ctx, "found file", map[string]any{"name": name, "layer_idx": i + 1})
if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {
return fmt.Errorf("create parent directories: %w", err)
}
destF, err := os.Create(destPath)
if err != nil {
return fmt.Errorf("create dest file for writing: %w", err)
}
defer destF.Close()
_, err = io.Copy(destF, tr)
if err != nil {
return fmt.Errorf("copy dest file from image: %w", err)
}
if err := destF.Close(); err != nil {
return fmt.Errorf("close dest file: %w", err)
}

if err := os.Chmod(destPath, 0o755); err != nil {
return fmt.Errorf("chmod file: %w", err)
}
return nil
}
}

return fmt.Errorf("extract envbuilder binary from image %q: %w", imgRef, os.ErrNotExist)
}
Loading