Skip to content

Commit 482a446

Browse files
authored
chore(internal/provider): refactor cached_image_resource (#46)
Addresses some non-blocking comments from #44: - Extracts some of the functions in cached_image_resource.go to separate internal packages tfutil and imgutil. - Some other functions are extracted to helpers.go. - Extracts non-overridable flags to a package-level variable. - Pre-allocates some slices where possible. - Removes some unused code and renames some existing code for readability
1 parent 23f2cf5 commit 482a446

File tree

7 files changed

+472
-420
lines changed

7 files changed

+472
-420
lines changed

internal/imgutil/imgutil.go

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package imgutil
2+
3+
import (
4+
"archive/tar"
5+
"context"
6+
"fmt"
7+
"io"
8+
"os"
9+
"path/filepath"
10+
11+
"github.com/coder/envbuilder/constants"
12+
"github.com/google/go-containerregistry/pkg/authn"
13+
"github.com/google/go-containerregistry/pkg/name"
14+
v1 "github.com/google/go-containerregistry/pkg/v1"
15+
"github.com/google/go-containerregistry/pkg/v1/remote"
16+
"github.com/hashicorp/terraform-plugin-log/tflog"
17+
)
18+
19+
// GetRemoteImage fetches the image manifest of the image.
20+
func GetRemoteImage(imgRef string) (v1.Image, error) {
21+
ref, err := name.ParseReference(imgRef)
22+
if err != nil {
23+
return nil, fmt.Errorf("parse reference: %w", err)
24+
}
25+
26+
img, err := remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
27+
if err != nil {
28+
return nil, fmt.Errorf("check remote image: %w", err)
29+
}
30+
31+
return img, nil
32+
}
33+
34+
// ExtractEnvbuilderFromImage reads the image located at imgRef and extracts
35+
// MagicBinaryLocation to destPath.
36+
func ExtractEnvbuilderFromImage(ctx context.Context, imgRef, destPath string) error {
37+
needle := filepath.Clean(constants.MagicBinaryLocation)[1:] // skip leading '/'
38+
img, err := GetRemoteImage(imgRef)
39+
if err != nil {
40+
return fmt.Errorf("check remote image: %w", err)
41+
}
42+
43+
layers, err := img.Layers()
44+
if err != nil {
45+
return fmt.Errorf("get image layers: %w", err)
46+
}
47+
48+
// Check the layers in reverse order. The last layers are more likely to
49+
// include the binary.
50+
for i := len(layers) - 1; i >= 0; i-- {
51+
ul, err := layers[i].Uncompressed()
52+
if err != nil {
53+
return fmt.Errorf("get uncompressed layer: %w", err)
54+
}
55+
56+
tr := tar.NewReader(ul)
57+
for {
58+
th, err := tr.Next()
59+
if err == io.EOF {
60+
break
61+
}
62+
63+
if err != nil {
64+
return fmt.Errorf("read tar header: %w", err)
65+
}
66+
67+
name := filepath.Clean(th.Name)
68+
if th.Typeflag != tar.TypeReg {
69+
tflog.Debug(ctx, "skip non-regular file", map[string]any{"name": name, "layer_idx": i + 1})
70+
continue
71+
}
72+
73+
if name != needle {
74+
tflog.Debug(ctx, "skip file", map[string]any{"name": name, "layer_idx": i + 1})
75+
continue
76+
}
77+
78+
tflog.Debug(ctx, "found file", map[string]any{"name": name, "layer_idx": i + 1})
79+
if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {
80+
return fmt.Errorf("create parent directories: %w", err)
81+
}
82+
destF, err := os.Create(destPath)
83+
if err != nil {
84+
return fmt.Errorf("create dest file for writing: %w", err)
85+
}
86+
defer destF.Close()
87+
_, err = io.Copy(destF, tr)
88+
if err != nil {
89+
return fmt.Errorf("copy dest file from image: %w", err)
90+
}
91+
if err := destF.Close(); err != nil {
92+
return fmt.Errorf("close dest file: %w", err)
93+
}
94+
95+
if err := os.Chmod(destPath, 0o755); err != nil {
96+
return fmt.Errorf("chmod file: %w", err)
97+
}
98+
return nil
99+
}
100+
}
101+
102+
return fmt.Errorf("extract envbuilder binary from image %q: %w", imgRef, os.ErrNotExist)
103+
}

0 commit comments

Comments
 (0)