Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b1cdfcc

Browse files
committed
fix: skip /var/run on unpack
This resolves coder/coder#8540.
1 parent 0968214 commit b1cdfcc

File tree

2 files changed

+84
-35
lines changed

2 files changed

+84
-35
lines changed

envbuilder.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,13 @@ type Options struct {
137137
// and pulling from container registries.
138138
Insecure bool `env:"INSECURE"`
139139

140+
// SkipRebuild skips building if the MagicFile exists.
141+
// This is used to skip building when a container is
142+
// restarting. e.g. docker stop -> docker start
143+
// This value can always be set to true - even if the
144+
// container is being started for the first time.
145+
SkipRebuild bool `env:"SKIP_REBUILD"`
146+
140147
// GitURL is the URL of the Git repository to clone.
141148
// This is optional!
142149
GitURL string `env:"GIT_URL"`
@@ -464,17 +471,24 @@ func Run(ctx context.Context, options Options) error {
464471
// IgnorePaths in the Kaniko options doesn't properly ignore paths.
465472
// So we add them to the default ignore list. See:
466473
// https://github.com/GoogleContainerTools/kaniko/blob/63be4990ca5a60bdf06ddc4d10aa4eca0c0bc714/cmd/executor/cmd/root.go#L136
467-
ignorePaths := []string{MagicDir, options.LayerCacheDir, options.WorkspaceFolder}
474+
ignorePaths := []string{
475+
MagicDir,
476+
options.LayerCacheDir,
477+
options.WorkspaceFolder,
478+
// Required for devcontainer to ignore directories like /var/run/secrets,
479+
// which frequently has mounted read-only runtime secrets.
480+
"/var/run",
481+
}
468482
for _, ignorePath := range ignorePaths {
469483
util.AddToDefaultIgnoreList(util.IgnoreListEntry{
470484
Path: ignorePath,
471-
PrefixMatchOnly: true,
485+
PrefixMatchOnly: false,
472486
})
473487
}
474488

475489
build := func() (v1.Image, error) {
476490
_, err := options.Filesystem.Stat(MagicFile)
477-
if err == nil {
491+
if err == nil && options.SkipRebuild {
478492
endStage := startStage("🏗️ Skipping build because of cache...")
479493
imageRef, err := devcontainer.ImageFromDockerfile(buildParams.DockerfileContent)
480494
if err != nil {
@@ -557,6 +571,10 @@ func Run(ctx context.Context, options Options) error {
557571
case strings.Contains(err.Error(), "authentication required"):
558572
fallback = true
559573
fallbackErr = err
574+
// This occurs from Docker Hub when the image cannot be found!
575+
case strings.Contains(err.Error(), "manifest unknown"):
576+
fallback = true
577+
fallbackErr = err
560578
case strings.Contains(err.Error(), "unexpected status code 401 Unauthorized"):
561579
logf(codersdk.LogLevelError, "Unable to pull the provided image. Ensure your registry credentials are correct!")
562580
}

integration/integration_test.go

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import (
1414
"net/http/httptest"
1515
"net/http/httputil"
1616
"net/url"
17+
"os"
1718
"os/exec"
19+
"path/filepath"
1820
"strings"
1921
"testing"
2022
"time"
@@ -52,9 +54,9 @@ func TestFailsGitAuth(t *testing.T) {
5254
username: "kyle",
5355
password: "testing",
5456
})
55-
_, err := runEnvbuilder(t, []string{
57+
_, err := runEnvbuilder(t, options{env: []string{
5658
"GIT_URL=" + url,
57-
})
59+
}})
5860
require.ErrorContains(t, err, "authentication required")
5961
}
6062

@@ -67,12 +69,12 @@ func TestSucceedsGitAuth(t *testing.T) {
6769
username: "kyle",
6870
password: "testing",
6971
})
70-
_, err := runEnvbuilder(t, []string{
72+
_, err := runEnvbuilder(t, options{env: []string{
7173
"GIT_URL=" + url,
7274
"DOCKERFILE_PATH=Dockerfile",
7375
"GIT_USERNAME=kyle",
7476
"GIT_PASSWORD=testing",
75-
})
77+
}})
7678
require.NoError(t, err)
7779
}
7880

@@ -111,9 +113,9 @@ func TestBuildFromDevcontainerWithFeatures(t *testing.T) {
111113
".devcontainer/Dockerfile": "FROM ubuntu",
112114
},
113115
})
114-
ctr, err := runEnvbuilder(t, []string{
116+
ctr, err := runEnvbuilder(t, options{env: []string{
115117
"GIT_URL=" + url,
116-
})
118+
}})
117119
require.NoError(t, err)
118120

119121
output := execContainer(t, ctr, "cat /test")
@@ -127,9 +129,32 @@ func TestBuildFromDockerfile(t *testing.T) {
127129
"Dockerfile": "FROM alpine:latest",
128130
},
129131
})
130-
ctr, err := runEnvbuilder(t, []string{
132+
ctr, err := runEnvbuilder(t, options{env: []string{
131133
"GIT_URL=" + url,
132134
"DOCKERFILE_PATH=Dockerfile",
135+
}})
136+
require.NoError(t, err)
137+
138+
output := execContainer(t, ctr, "echo hello")
139+
require.Equal(t, "hello", strings.TrimSpace(output))
140+
}
141+
142+
func TestBuildIgnoreVarRun(t *testing.T) {
143+
// Ensures that a Git repository with a Dockerfile is cloned and built.
144+
url := createGitServer(t, gitServerOptions{
145+
files: map[string]string{
146+
"Dockerfile": "FROM alpine:latest",
147+
},
148+
})
149+
dir := t.TempDir()
150+
err := os.WriteFile(filepath.Join(dir, "secret"), []byte("test"), 0644)
151+
require.NoError(t, err)
152+
ctr, err := runEnvbuilder(t, options{
153+
env: []string{
154+
"GIT_URL=" + url,
155+
"DOCKERFILE_PATH=Dockerfile",
156+
},
157+
binds: []string{fmt.Sprintf("%s:/var/run/secrets", dir)},
133158
})
134159
require.NoError(t, err)
135160

@@ -144,11 +169,11 @@ func TestBuildWithSetupScript(t *testing.T) {
144169
"Dockerfile": "FROM alpine:latest",
145170
},
146171
})
147-
ctr, err := runEnvbuilder(t, []string{
172+
ctr, err := runEnvbuilder(t, options{env: []string{
148173
"GIT_URL=" + url,
149174
"DOCKERFILE_PATH=Dockerfile",
150175
"SETUP_SCRIPT=echo \"INIT_ARGS=-c 'echo hi > /wow && sleep infinity'\" >> $ENVBUILDER_ENV",
151-
})
176+
}})
152177
require.NoError(t, err)
153178

154179
output := execContainer(t, ctr, "cat /wow")
@@ -161,14 +186,14 @@ func TestBuildCustomCertificates(t *testing.T) {
161186
"Dockerfile": "FROM alpine:latest",
162187
},
163188
}))
164-
ctr, err := runEnvbuilder(t, []string{
189+
ctr, err := runEnvbuilder(t, options{env: []string{
165190
"GIT_URL=" + srv.URL,
166191
"DOCKERFILE_PATH=Dockerfile",
167192
"SSL_CERT_BASE64=" + base64.StdEncoding.EncodeToString(pem.EncodeToMemory(&pem.Block{
168193
Type: "CERTIFICATE",
169194
Bytes: srv.TLS.Certificates[0].Certificate[0],
170195
})),
171-
})
196+
}})
172197
require.NoError(t, err)
173198

174199
output := execContainer(t, ctr, "echo hello")
@@ -182,10 +207,10 @@ func TestBuildStopStartCached(t *testing.T) {
182207
"Dockerfile": "FROM alpine:latest",
183208
},
184209
})
185-
ctr, err := runEnvbuilder(t, []string{
210+
ctr, err := runEnvbuilder(t, options{env: []string{
186211
"GIT_URL=" + url,
187212
"DOCKERFILE_PATH=Dockerfile",
188-
})
213+
}})
189214
require.NoError(t, err)
190215

191216
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
@@ -212,9 +237,9 @@ func TestCloneFailsFallback(t *testing.T) {
212237
t.Parallel()
213238
t.Run("BadRepo", func(t *testing.T) {
214239
t.Parallel()
215-
_, err := runEnvbuilder(t, []string{
240+
_, err := runEnvbuilder(t, options{env: []string{
216241
"GIT_URL=bad-value",
217-
})
242+
}})
218243
require.ErrorContains(t, err, envbuilder.ErrNoFallbackImage.Error())
219244
})
220245
}
@@ -229,10 +254,10 @@ func TestBuildFailsFallback(t *testing.T) {
229254
"Dockerfile": "bad syntax",
230255
},
231256
})
232-
_, err := runEnvbuilder(t, []string{
257+
_, err := runEnvbuilder(t, options{env: []string{
233258
"GIT_URL=" + url,
234259
"DOCKERFILE_PATH=Dockerfile",
235-
})
260+
}})
236261
require.ErrorContains(t, err, envbuilder.ErrNoFallbackImage.Error())
237262
require.ErrorContains(t, err, "dockerfile parse error")
238263
})
@@ -245,10 +270,10 @@ func TestBuildFailsFallback(t *testing.T) {
245270
RUN exit 1`,
246271
},
247272
})
248-
_, err := runEnvbuilder(t, []string{
273+
_, err := runEnvbuilder(t, options{env: []string{
249274
"GIT_URL=" + url,
250275
"DOCKERFILE_PATH=Dockerfile",
251-
})
276+
}})
252277
require.ErrorContains(t, err, envbuilder.ErrNoFallbackImage.Error())
253278
})
254279
t.Run("BadDevcontainer", func(t *testing.T) {
@@ -259,9 +284,9 @@ RUN exit 1`,
259284
".devcontainer/devcontainer.json": "not json",
260285
},
261286
})
262-
_, err := runEnvbuilder(t, []string{
287+
_, err := runEnvbuilder(t, options{env: []string{
263288
"GIT_URL=" + url,
264-
})
289+
}})
265290
require.ErrorContains(t, err, envbuilder.ErrNoFallbackImage.Error())
266291
})
267292
t.Run("NoImageOrDockerfile", func(t *testing.T) {
@@ -271,10 +296,10 @@ RUN exit 1`,
271296
".devcontainer/devcontainer.json": "{}",
272297
},
273298
})
274-
ctr, err := runEnvbuilder(t, []string{
299+
ctr, err := runEnvbuilder(t, options{env: []string{
275300
"GIT_URL=" + url,
276301
"FALLBACK_IMAGE=alpine:latest",
277-
})
302+
}})
278303
require.NoError(t, err)
279304

280305
output := execContainer(t, ctr, "echo hello")
@@ -297,10 +322,10 @@ func TestPrivateRegistry(t *testing.T) {
297322
"Dockerfile": "FROM " + image,
298323
},
299324
})
300-
_, err := runEnvbuilder(t, []string{
325+
_, err := runEnvbuilder(t, options{env: []string{
301326
"GIT_URL=" + url,
302327
"DOCKERFILE_PATH=Dockerfile",
303-
})
328+
}})
304329
require.ErrorContains(t, err, "Unauthorized")
305330
})
306331
t.Run("Auth", func(t *testing.T) {
@@ -326,11 +351,11 @@ func TestPrivateRegistry(t *testing.T) {
326351
})
327352
require.NoError(t, err)
328353

329-
_, err = runEnvbuilder(t, []string{
354+
_, err = runEnvbuilder(t, options{env: []string{
330355
"GIT_URL=" + url,
331356
"DOCKERFILE_PATH=Dockerfile",
332357
"DOCKER_CONFIG_BASE64=" + base64.StdEncoding.EncodeToString(config),
333-
})
358+
}})
334359
require.NoError(t, err)
335360
})
336361
t.Run("InvalidAuth", func(t *testing.T) {
@@ -356,11 +381,11 @@ func TestPrivateRegistry(t *testing.T) {
356381
})
357382
require.NoError(t, err)
358383

359-
_, err = runEnvbuilder(t, []string{
384+
_, err = runEnvbuilder(t, options{env: []string{
360385
"GIT_URL=" + url,
361386
"DOCKERFILE_PATH=Dockerfile",
362387
"DOCKER_CONFIG_BASE64=" + base64.StdEncoding.EncodeToString(config),
363-
})
388+
}})
364389
require.ErrorContains(t, err, "Unauthorized")
365390
})
366391
}
@@ -409,7 +434,7 @@ func setupPassthroughRegistry(t *testing.T, image string, auth *registryAuth) st
409434
}
410435

411436
func TestNoMethodFails(t *testing.T) {
412-
_, err := runEnvbuilder(t, []string{})
437+
_, err := runEnvbuilder(t, options{env: []string{}})
413438
require.ErrorContains(t, err, envbuilder.ErrNoFallbackImage.Error())
414439
}
415440

@@ -509,9 +534,14 @@ func cleanOldEnvbuilders() {
509534
}
510535
}
511536

537+
type options struct {
538+
binds []string
539+
env []string
540+
}
541+
512542
// runEnvbuilder starts the envbuilder container with the given environment
513543
// variables and returns the container ID.
514-
func runEnvbuilder(t *testing.T, env []string) (string, error) {
544+
func runEnvbuilder(t *testing.T, options options) (string, error) {
515545
t.Helper()
516546
ctx := context.Background()
517547
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
@@ -521,12 +551,13 @@ func runEnvbuilder(t *testing.T, env []string) (string, error) {
521551
})
522552
ctr, err := cli.ContainerCreate(ctx, &container.Config{
523553
Image: "envbuilder:latest",
524-
Env: env,
554+
Env: options.env,
525555
Labels: map[string]string{
526556
testContainerLabel: "true",
527557
},
528558
}, &container.HostConfig{
529559
NetworkMode: container.NetworkMode("host"),
560+
Binds: options.binds,
530561
}, nil, nil, "")
531562
require.NoError(t, err)
532563
t.Cleanup(func() {

0 commit comments

Comments
 (0)