Skip to content

Commit 90c5aa3

Browse files
author
Natalie Arellano
committed
WIP
Signed-off-by: Natalie Arellano <[email protected]>
1 parent 80e8c22 commit 90c5aa3

File tree

11 files changed

+399
-239
lines changed

11 files changed

+399
-239
lines changed

cmd/lifecycle/creator.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,15 @@ func (c *createCmd) Exec() error {
124124
plan files.Plan
125125
)
126126
cmd.DefaultLogger.Phase("ANALYZING")
127-
analyzerFactory := phase.NewConnectedFactory(
127+
connectedFactory := phase.NewConnectedFactory(
128128
c.PlatformAPI,
129129
&cmd.BuildpackAPIVerifier{},
130130
NewCacheHandler(c.keychain),
131131
files.NewHandler(),
132132
image.NewHandler(c.docker, c.keychain, c.LayoutDir, c.UseLayout, c.InsecureRegistries),
133133
image.NewRegistryHandler(c.keychain, c.InsecureRegistries),
134134
)
135-
analyzer, err := analyzerFactory.NewAnalyzer(c.Inputs(), cmd.DefaultLogger)
135+
analyzer, err := connectedFactory.NewAnalyzer(c.Inputs(), cmd.DefaultLogger)
136136
if err != nil {
137137
return unwrapErrorFailWithMessage(err, "initialize analyzer")
138138
}
@@ -146,13 +146,13 @@ func (c *createCmd) Exec() error {
146146

147147
// Detect
148148
cmd.DefaultLogger.Phase("DETECTING")
149-
detectorFactory := phase.NewHermeticFactory(
149+
hermeticFactory := phase.NewHermeticFactory(
150150
c.PlatformAPI,
151151
&cmd.BuildpackAPIVerifier{},
152152
files.NewHandler(),
153153
dirStore,
154154
)
155-
detector, err := detectorFactory.NewDetector(c.Inputs(), cmd.DefaultLogger)
155+
detector, err := hermeticFactory.NewDetector(c.Inputs(), cmd.DefaultLogger)
156156
if err != nil {
157157
return unwrapErrorFailWithMessage(err, "initialize detector")
158158
}
@@ -171,12 +171,12 @@ func (c *createCmd) Exec() error {
171171
// Restore
172172
if !c.SkipLayers || c.PlatformAPI.AtLeast("0.10") {
173173
cmd.DefaultLogger.Phase("RESTORING")
174-
restoreCmd := &restoreCmd{
175-
Platform: c.Platform,
176-
keychain: c.keychain,
174+
restorer, err := connectedFactory.NewRestorer(c.Inputs(), cmd.DefaultLogger, buildpack.Group{})
175+
if err != nil {
176+
return unwrapErrorFailWithMessage(err, "initialize restorer")
177177
}
178-
if err := restoreCmd.restore(analyzedMD.LayersMetadata, group, cacheStore); err != nil {
179-
return err
178+
if err = restorer.RestoreCache(); err != nil {
179+
return cmd.FailErrCode(err, c.CodeFor(platform.RestoreError), "restore")
180180
}
181181
}
182182

cmd/lifecycle/restorer.go

Lines changed: 14 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,7 @@ package main
33
import (
44
"errors"
55
"fmt"
6-
"os"
7-
"path/filepath"
86

9-
"github.com/buildpacks/imgutil"
10-
"github.com/buildpacks/imgutil/layout"
11-
"github.com/buildpacks/imgutil/layout/sparse"
12-
"github.com/buildpacks/imgutil/remote"
137
"github.com/docker/docker/client"
148
"github.com/google/go-containerregistry/pkg/authn"
159

@@ -18,16 +12,12 @@ import (
1812
"github.com/buildpacks/lifecycle/cmd"
1913
"github.com/buildpacks/lifecycle/cmd/lifecycle/cli"
2014
"github.com/buildpacks/lifecycle/image"
21-
"github.com/buildpacks/lifecycle/internal/encoding"
22-
"github.com/buildpacks/lifecycle/internal/layer"
2315
"github.com/buildpacks/lifecycle/phase"
2416
"github.com/buildpacks/lifecycle/platform"
2517
"github.com/buildpacks/lifecycle/platform/files"
2618
"github.com/buildpacks/lifecycle/priv"
2719
)
2820

29-
const kanikoDir = "/kaniko"
30-
3121
type restoreCmd struct {
3222
*platform.Platform
3323

@@ -95,196 +85,25 @@ func (r *restoreCmd) Privileges() error {
9585
}
9686

9787
func (r *restoreCmd) Exec() error {
98-
group, err := files.Handler.ReadGroup(r.GroupPath)
99-
if err != nil {
100-
return err
101-
}
102-
if err = verifyBuildpackApis(group); err != nil {
103-
return err
104-
}
105-
106-
var analyzedMD files.Analyzed
107-
if analyzedMD, err = files.Handler.ReadAnalyzed(r.AnalyzedPath, cmd.DefaultLogger); err == nil {
108-
if r.supportsBuildImageExtension() && r.BuildImageRef != "" {
109-
cmd.DefaultLogger.Debugf("Pulling builder image metadata for %s...", r.BuildImageRef)
110-
remoteBuildImage, err := r.pullSparse(r.BuildImageRef)
111-
if err != nil {
112-
return cmd.FailErr(err, fmt.Sprintf("pull builder image %s", r.BuildImageRef))
113-
}
114-
digestRef, err := remoteBuildImage.Identifier()
115-
if err != nil {
116-
return cmd.FailErr(err, "get digest reference for builder image")
117-
}
118-
analyzedMD.BuildImage = &files.ImageIdentifier{Reference: digestRef.String()}
119-
cmd.DefaultLogger.Debugf("Adding build image info to analyzed metadata: ")
120-
cmd.DefaultLogger.Debugf(encoding.ToJSONMaybe(analyzedMD.BuildImage))
121-
}
122-
var (
123-
runImage imgutil.Image
124-
)
125-
runImageName := analyzedMD.RunImageImage() // FIXME: if we have a digest reference available in `Reference` (e.g., in the non-daemon case) we should use it
126-
if r.supportsRunImageExtension() && needsPulling(analyzedMD.RunImage) {
127-
cmd.DefaultLogger.Debugf("Pulling run image metadata for %s...", runImageName)
128-
runImage, err = r.pullSparse(runImageName)
129-
if err != nil {
130-
return cmd.FailErr(err, fmt.Sprintf("pull run image %s", runImageName))
131-
}
132-
// update analyzed metadata, even if we only needed to pull the image metadata, because
133-
// the extender needs a digest reference in analyzed.toml,
134-
// and daemon images will only have a daemon image ID
135-
if err = r.updateAnalyzedMD(&analyzedMD, runImage); err != nil {
136-
return cmd.FailErr(err, "update analyzed metadata")
137-
}
138-
} else if r.needsUpdating(analyzedMD.RunImage, group) {
139-
cmd.DefaultLogger.Debugf("Updating run image info in analyzed metadata...")
140-
h := image.NewHandler(r.docker, r.keychain, r.LayoutDir, r.UseLayout, r.InsecureRegistries)
141-
runImage, err = h.InitImage(runImageName)
142-
if err != nil || !runImage.Found() {
143-
return cmd.FailErr(err, fmt.Sprintf("get run image %s", runImageName))
144-
}
145-
if err = r.updateAnalyzedMD(&analyzedMD, runImage); err != nil {
146-
return cmd.FailErr(err, "update analyzed metadata")
147-
}
148-
}
149-
if err = files.Handler.WriteAnalyzed(r.AnalyzedPath, &analyzedMD, cmd.DefaultLogger); err != nil {
150-
return cmd.FailErr(err, "write analyzed metadata")
151-
}
152-
} else {
153-
cmd.DefaultLogger.Warnf("Not using analyzed data, usable file not found: %s", err)
154-
}
155-
156-
cacheStore, err := initCache(r.CacheImageRef, r.CacheDir, r.keychain, r.PlatformAPI.LessThan("0.13"))
157-
if err != nil {
158-
return err
159-
}
160-
return r.restore(analyzedMD.LayersMetadata, group, cacheStore)
161-
}
162-
163-
func (r *restoreCmd) updateAnalyzedMD(analyzedMD *files.Analyzed, runImage imgutil.Image) error {
164-
if r.PlatformAPI.LessThan("0.10") {
165-
return nil
166-
}
167-
digestRef, err := runImage.Identifier()
168-
if err != nil {
169-
return cmd.FailErr(err, "get digest reference for run image")
170-
}
171-
var targetData *files.TargetMetadata
172-
if r.PlatformAPI.AtLeast("0.12") {
173-
targetData, err = platform.GetTargetMetadata(runImage)
174-
if err != nil {
175-
return cmd.FailErr(err, "read target data from run image")
176-
}
177-
}
178-
cmd.DefaultLogger.Debugf("Run image info in analyzed metadata was: ")
179-
cmd.DefaultLogger.Debugf(encoding.ToJSONMaybe(analyzedMD.RunImage))
180-
analyzedMD.RunImage.Reference = digestRef.String()
181-
analyzedMD.RunImage.TargetMetadata = targetData
182-
cmd.DefaultLogger.Debugf("Run image info in analyzed metadata is: ")
183-
cmd.DefaultLogger.Debugf(encoding.ToJSONMaybe(analyzedMD.RunImage))
184-
return nil
185-
}
186-
187-
func needsPulling(runImage *files.RunImage) bool {
188-
if runImage == nil {
189-
// sanity check to prevent panic, should be unreachable
190-
return false
191-
}
192-
return runImage.Extend
193-
}
194-
195-
func (r *restoreCmd) needsUpdating(runImage *files.RunImage, group buildpack.Group) bool {
196-
if r.PlatformAPI.LessThan("0.10") {
197-
return false
198-
}
199-
if !group.HasExtensions() {
200-
return false
201-
}
202-
if runImage == nil {
203-
// sanity check to prevent panic, should be unreachable
204-
return false
205-
}
206-
if isPopulated(runImage.TargetMetadata) {
207-
return false
208-
}
209-
return true
210-
}
211-
212-
func isPopulated(metadata *files.TargetMetadata) bool {
213-
return metadata != nil && metadata.OS != ""
214-
}
215-
216-
func (r *restoreCmd) supportsBuildImageExtension() bool {
217-
return r.PlatformAPI.AtLeast("0.10")
218-
}
219-
220-
func (r *restoreCmd) supportsRunImageExtension() bool {
221-
return r.PlatformAPI.AtLeast("0.12") && !r.UseLayout // FIXME: add layout support as part of https://github.com/buildpacks/lifecycle/issues/1102
222-
}
223-
224-
func (r *restoreCmd) supportsTargetData() bool {
225-
return r.PlatformAPI.AtLeast("0.12")
226-
}
227-
228-
func (r *restoreCmd) pullSparse(imageRef string) (imgutil.Image, error) {
229-
baseCacheDir := filepath.Join(kanikoDir, "cache", "base")
230-
if err := os.MkdirAll(baseCacheDir, 0755); err != nil {
231-
return nil, fmt.Errorf("failed to create cache directory: %w", err)
232-
}
233-
234-
var opts []imgutil.ImageOption
235-
opts = append(opts, append(image.GetInsecureOptions(r.InsecureRegistries), remote.FromBaseImage(imageRef))...)
236-
237-
// get remote image
238-
remoteImage, err := remote.NewImage(imageRef, r.keychain, opts...)
239-
if err != nil {
240-
return nil, fmt.Errorf("failed to initialize remote image: %w", err)
241-
}
242-
if !remoteImage.Found() {
243-
return nil, fmt.Errorf("failed to get remote image")
244-
}
245-
// check for usable kaniko dir
246-
if _, err := os.Stat(kanikoDir); err != nil {
247-
if !os.IsNotExist(err) {
248-
return nil, fmt.Errorf("failed to read kaniko directory: %w", err)
249-
}
250-
return nil, nil
251-
}
252-
// save to disk
253-
h, err := remoteImage.UnderlyingImage().Digest()
254-
if err != nil {
255-
return nil, fmt.Errorf("failed to get remote image digest: %w", err)
256-
}
257-
path := filepath.Join(baseCacheDir, h.String())
258-
cmd.DefaultLogger.Debugf("Saving image metadata to %s...", path)
259-
sparseImage, err := sparse.NewImage(
260-
path,
261-
remoteImage.UnderlyingImage(),
262-
layout.WithMediaTypes(imgutil.DefaultTypes),
88+
factory := phase.NewConnectedFactory(
89+
r.PlatformAPI,
90+
&cmd.BuildpackAPIVerifier{},
91+
NewCacheHandler(r.keychain),
92+
files.Handler,
93+
image.NewHandler(r.docker, r.keychain, r.LayoutDir, r.UseLayout, r.InsecureRegistries),
94+
image.NewRegistryHandler(r.keychain, r.InsecureRegistries),
26395
)
96+
restorer, err := factory.NewRestorer(r.Inputs(), cmd.DefaultLogger, buildpack.Group{})
26497
if err != nil {
265-
return nil, fmt.Errorf("failed to initialize sparse image: %w", err)
98+
return unwrapErrorFailWithMessage(err, "initialize restorer")
26699
}
267-
if err = sparseImage.Save(); err != nil {
268-
return nil, fmt.Errorf("failed to save sparse image: %w", err)
100+
if err = restorer.RestoreAnalyzed(); err != nil {
101+
return cmd.FailErrCode(err, r.CodeFor(platform.RestoreError), "restore")
269102
}
270-
return remoteImage, nil
271-
}
272-
273-
func (r *restoreCmd) restore(layerMetadata files.LayersMetadata, group buildpack.Group, cacheStore phase.Cache) error {
274-
restorer := &phase.Restorer{
275-
LayersDir: r.LayersDir,
276-
Buildpacks: group.Group,
277-
Logger: cmd.DefaultLogger,
278-
PlatformAPI: r.PlatformAPI,
279-
LayerMetadataRestorer: layer.NewDefaultMetadataRestorer(r.LayersDir, r.SkipLayers, cmd.DefaultLogger),
280-
LayersMetadata: layerMetadata,
281-
SBOMRestorer: layer.NewSBOMRestorer(layer.SBOMRestorerOpts{
282-
LayersDir: r.LayersDir,
283-
Logger: cmd.DefaultLogger,
284-
Nop: r.SkipLayers,
285-
}, r.PlatformAPI),
103+
if err = files.Handler.WriteAnalyzed(r.AnalyzedPath, &restorer.AnalyzedMD, cmd.DefaultLogger); err != nil {
104+
return cmd.FailErr(err, "write analyzed metadata")
286105
}
287-
if err := restorer.Restore(cacheStore); err != nil {
106+
if err = restorer.RestoreCache(); err != nil {
288107
return cmd.FailErrCode(err, r.CodeFor(platform.RestoreError), "restore")
289108
}
290109
return nil

image/handler.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
//go:generate mockgen -package testmock -destination ../phase/testmock/image_handler.go github.com/buildpacks/lifecycle/image Handler
1515
type Handler interface {
1616
InitImage(imageRef string) (imgutil.Image, error)
17+
InitRemoteImage(imageRef string) (imgutil.Image, error)
1718
Kind() string
1819
}
1920

@@ -22,15 +23,25 @@ type Handler interface {
2223
// - WHEN a docker client is provided then it returns a LocalHandler
2324
// - WHEN an auth.Keychain is provided then it returns a RemoteHandler
2425
// - Otherwise nil is returned
25-
func NewHandler(docker client.CommonAPIClient, keychain authn.Keychain, layoutDir string, useLayout bool, insecureRegistries []string) Handler {
26+
func NewHandler(
27+
docker client.CommonAPIClient,
28+
keychain authn.Keychain,
29+
layoutDir string,
30+
useLayout bool,
31+
insecureRegistries []string,
32+
) Handler {
2633
if layoutDir != "" && useLayout {
2734
return &LayoutHandler{
28-
layoutDir: layoutDir,
35+
layoutDir: layoutDir,
36+
keychain: keychain,
37+
insecureRegistries: insecureRegistries,
2938
}
3039
}
3140
if docker != nil {
3241
return &LocalHandler{
33-
docker: docker,
42+
docker: docker,
43+
keychain: keychain,
44+
insecureRegistries: insecureRegistries,
3445
}
3546
}
3647
if keychain != nil {

image/layout_handler.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ import (
88

99
"github.com/buildpacks/imgutil"
1010
"github.com/buildpacks/imgutil/layout"
11+
"github.com/buildpacks/imgutil/remote"
12+
"github.com/google/go-containerregistry/pkg/authn"
1113
v1 "github.com/google/go-containerregistry/pkg/v1"
1214
)
1315

1416
const LayoutKind = "layout"
1517

1618
type LayoutHandler struct {
17-
layoutDir string
19+
layoutDir string
20+
keychain authn.Keychain
21+
insecureRegistries []string
1822
}
1923

2024
func (h *LayoutHandler) InitImage(imageRef string) (imgutil.Image, error) {
@@ -29,6 +33,25 @@ func (h *LayoutHandler) InitImage(imageRef string) (imgutil.Image, error) {
2933
return layout.NewImage(path, layout.FromBaseImagePath(path))
3034
}
3135

36+
// InitRemoteImage TODO
37+
func (h *LayoutHandler) InitRemoteImage(imageRef string) (imgutil.Image, error) {
38+
if imageRef == "" {
39+
return nil, nil
40+
}
41+
42+
options := []imgutil.ImageOption{
43+
remote.FromBaseImage(imageRef),
44+
}
45+
46+
options = append(options, GetInsecureOptions(h.insecureRegistries)...)
47+
48+
return remote.NewImage(
49+
imageRef,
50+
h.keychain,
51+
options...,
52+
)
53+
}
54+
3255
func (h *LayoutHandler) Kind() string {
3356
return LayoutKind
3457
}

0 commit comments

Comments
 (0)