Skip to content

Commit de293b8

Browse files
authored
Update envd on first layer build (#941)
1 parent 7849acc commit de293b8

File tree

3 files changed

+100
-17
lines changed

3 files changed

+100
-17
lines changed

packages/orchestrator/internal/template/build/build_layer.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/fc"
1616
sbxtemplate "github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/template"
1717
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/config"
18+
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/envd"
1819
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/sandboxtools"
1920
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/writer"
2021
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/constants"
@@ -36,6 +37,7 @@ func (b *Builder) buildLayer(
3637
sourceMeta LayerMetadata,
3738
exportTemplate storage.TemplateFiles,
3839
resumeSandbox bool,
40+
updateEnvd bool,
3941
fn func(ctx context.Context, sbx *sandbox.Sandbox) (sandboxtools.CommandMetadata, error),
4042
) (LayerMetadata, error) {
4143
ctx, childSpan := b.tracer.Start(ctx, "run-in-sandbox")
@@ -170,6 +172,14 @@ func (b *Builder) buildLayer(
170172
b.proxy.RemoveFromPool(sbx.Metadata.Config.ExecutionId)
171173
}()
172174

175+
// Update envd binary to the latest version
176+
if updateEnvd {
177+
err = b.updateEnvdInSandbox(ctx, b.tracer, postProcessor, sbx)
178+
if err != nil {
179+
return LayerMetadata{}, fmt.Errorf("failed to update envd in sandbox: %w", err)
180+
}
181+
}
182+
173183
meta, err := fn(ctx, sbx)
174184
if err != nil {
175185
return LayerMetadata{}, fmt.Errorf("error running action in sandbox: %w", err)
@@ -199,6 +209,83 @@ func (b *Builder) buildLayer(
199209
return exportMeta, nil
200210
}
201211

212+
// updateEnvdInSandbox updates the envd binary in the sandbox to the latest version.
213+
func (b *Builder) updateEnvdInSandbox(
214+
ctx context.Context,
215+
tracer trace.Tracer,
216+
postProcessor *writer.PostProcessor,
217+
sbx *sandbox.Sandbox,
218+
) error {
219+
ctx, childSpan := tracer.Start(ctx, "update-envd")
220+
defer childSpan.End()
221+
222+
envdVersion, err := envd.GetEnvdVersion(ctx)
223+
if err != nil {
224+
return fmt.Errorf("error getting envd version: %w", err)
225+
}
226+
postProcessor.Debug(fmt.Sprintf("Updating envd to version v%s", envdVersion))
227+
228+
// Step 1: Copy the updated envd binary from host to /tmp in sandbox
229+
tmpEnvdPath := "/tmp/envd_updated"
230+
err = sandboxtools.CopyFile(
231+
ctx,
232+
b.tracer,
233+
b.proxy,
234+
sbx.Metadata.Config.SandboxId,
235+
"root",
236+
storage.HostEnvdPath,
237+
tmpEnvdPath,
238+
)
239+
if err != nil {
240+
return fmt.Errorf("failed to copy envd binary to sandbox: %w", err)
241+
}
242+
243+
// Step 2: Replace the binary
244+
replaceEnvdCmd := fmt.Sprintf(`
245+
# Replace the binary and set permissions
246+
chmod +x %s
247+
mv -f %s %s
248+
`, tmpEnvdPath, tmpEnvdPath, storage.GuestEnvdPath)
249+
250+
err = sandboxtools.RunCommandWithLogger(
251+
ctx,
252+
b.tracer,
253+
b.proxy,
254+
postProcessor,
255+
zap.DebugLevel,
256+
"update-envd-replace",
257+
sbx.Metadata.Config.SandboxId,
258+
replaceEnvdCmd,
259+
sandboxtools.CommandMetadata{User: "root"},
260+
)
261+
if err != nil {
262+
return fmt.Errorf("failed to replace envd binary: %w", err)
263+
}
264+
265+
// Step 3: Restart the systemd envd service
266+
// Error is ignored because it's expected the envd connection will be lost
267+
_ = sandboxtools.RunCommand(
268+
ctx,
269+
b.tracer,
270+
b.proxy,
271+
sbx.Metadata.Config.SandboxId,
272+
"systemctl restart envd",
273+
sandboxtools.CommandMetadata{User: "root"},
274+
)
275+
276+
// Step 4: Wait for envd to initialize
277+
err = sbx.WaitForEnvd(
278+
ctx,
279+
b.tracer,
280+
waitEnvdTimeout,
281+
)
282+
if err != nil {
283+
return fmt.Errorf("failed to wait for envd initialization after update: %w", err)
284+
}
285+
286+
return nil
287+
}
288+
202289
func pauseAndUpload(
203290
ctx context.Context,
204291
tracer trace.Tracer,

packages/orchestrator/internal/template/build/builder.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ func (b *Builder) Build(ctx context.Context, finalMetadata storage.TemplateFiles
163163
return nil, fmt.Errorf("error getting base hash: %w", err)
164164
}
165165

166-
lastCached, baseMetadata, err := b.setupBase(ctx, cacheScope, finalMetadata, template, lastHash, isV1Build)
166+
isLastLayerCached, baseMetadata, err := b.setupBase(ctx, cacheScope, finalMetadata, template, lastHash, isV1Build)
167167
if err != nil {
168168
return nil, fmt.Errorf("error setting up build: %w", err)
169169
}
@@ -183,10 +183,10 @@ func (b *Builder) Build(ctx context.Context, finalMetadata storage.TemplateFiles
183183
}
184184
baseSource = "FROM " + fromImage
185185
}
186-
postProcessor.Info(layerInfo(lastCached, "base", baseSource, lastHash))
186+
postProcessor.Info(layerInfo(isLastLayerCached, "base", baseSource, lastHash))
187187

188188
// Build the base layer if not cached
189-
if !lastCached {
189+
if !isLastLayerCached {
190190
templateBuildDir := filepath.Join(templatesDirectory, finalMetadata.BuildID)
191191
err = os.MkdirAll(templateBuildDir, 0o777)
192192
if err != nil {
@@ -349,9 +349,6 @@ func (b *Builder) Build(ctx context.Context, finalMetadata storage.TemplateFiles
349349

350350
sourceMetadata := baseMetadata
351351

352-
// First start is create (to change CPU, etc), subsequent starts are resume.
353-
shouldResumeSandbox := false
354-
355352
// Build Steps
356353
for i, step := range template.Steps {
357354
layerIndex := i + 1
@@ -385,7 +382,6 @@ func (b *Builder) Build(ctx context.Context, finalMetadata storage.TemplateFiles
385382
return nil, fmt.Errorf("error checking if layer is cached: %w", err)
386383
}
387384
isCached := !force && found
388-
lastCached = isCached
389385

390386
prefix := fmt.Sprintf("builder %d/%d", layerIndex, len(template.Steps))
391387
cmd := fmt.Sprintf("%s %s", strings.ToUpper(step.Type), strings.Join(step.Args, " "))
@@ -411,7 +407,9 @@ func (b *Builder) Build(ctx context.Context, finalMetadata storage.TemplateFiles
411407
lastHash,
412408
sourceMetadata,
413409
stepMetadata.Template,
414-
shouldResumeSandbox,
410+
// First not cached layer is create (to change CPU, etc), subsequent are resumes.
411+
!isLastLayerCached,
412+
isLastLayerCached,
415413
func(ctx context.Context, sbx *sandbox.Sandbox) (sandboxtools.CommandMetadata, error) {
416414
postProcessor.Debug(fmt.Sprintf("Running action in: %s/%s", sourceMetadata.Template.TemplateID, sourceMetadata.Template.BuildID))
417415

@@ -438,13 +436,15 @@ func (b *Builder) Build(ctx context.Context, finalMetadata storage.TemplateFiles
438436
}
439437
stepMetadata = meta
440438

441-
if !shouldResumeSandbox {
439+
// If the last layer is cached, update the base metadata to the step metadata
440+
// This is needed to properly resume the sandbox for the next step
441+
if isLastLayerCached {
442442
baseMetadata = stepMetadata
443-
shouldResumeSandbox = true
444443
}
445444
}
446445

447446
sourceMetadata = stepMetadata
447+
isLastLayerCached = isCached
448448
}
449449
// Build Steps
450450

@@ -487,7 +487,9 @@ func (b *Builder) Build(ctx context.Context, finalMetadata storage.TemplateFiles
487487
lastHash,
488488
sourceMetadata,
489489
finalMetadata,
490+
// Always restart the sandbox for the final layer to properly wire the rootfs path for the final template.
490491
false,
492+
isLastLayerCached,
491493
b.postProcessingFn(postProcessor, finalMetadata, sourceMetadata.Metadata, startMetadata),
492494
)
493495
if err != nil {

packages/orchestrator/internal/template/build/hash_index.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"strings"
1111

1212
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/config"
13-
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/envd"
1413
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/layerstorage"
1514
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/sandboxtools"
1615
"github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/utils"
@@ -84,11 +83,6 @@ func hashKeys(baseKey string, keys ...string) string {
8483
}
8584

8685
func hashBase(template config.TemplateConfig) (string, error) {
87-
envdHash, err := envd.GetEnvdHash()
88-
if err != nil {
89-
return "", fmt.Errorf("error getting envd binary hash: %w", err)
90-
}
91-
9286
var baseSource string
9387
if template.FromTemplate != nil {
9488
// When building from template, use the base template metadata
@@ -103,7 +97,7 @@ func hashBase(template config.TemplateConfig) (string, error) {
10397
baseSource = template.FromImage
10498
}
10599

106-
return hashKeys(hashingVersion, envdHash, provisionScriptFile, strconv.FormatInt(template.DiskSizeMB, 10), baseSource), nil
100+
return hashKeys(hashingVersion, provisionScriptFile, strconv.FormatInt(template.DiskSizeMB, 10), baseSource), nil
107101
}
108102

109103
func hashStep(previousHash string, step *templatemanager.TemplateStep) string {

0 commit comments

Comments
 (0)