Skip to content

Commit 3a7b9f6

Browse files
committed
polish cdebug exec new pull if not present logic (docker only)
1 parent f0f8b4d commit 3a7b9f6

File tree

4 files changed

+81
-81
lines changed

4 files changed

+81
-81
lines changed

cmd/exec/exec_docker.go

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"io"
7+
"strings"
78

89
"github.com/docker/docker/api/types"
910
"github.com/docker/docker/api/types/container"
@@ -16,39 +17,6 @@ import (
1617
"github.com/iximiuz/cdebug/pkg/uuid"
1718
)
1819

19-
// debugImageExistsLocally checks if the debug image exists in the host and that it matches the target container
20-
// platform.
21-
func debugImageExistsLocally(ctx context.Context, client *docker.Client, debugImage string, debugImagePlatform string, target types.ContainerJSON) (bool, error) {
22-
debugImageInspect, _, err := client.ImageInspectWithRaw(ctx, debugImage)
23-
if err != nil {
24-
// err means that the requested image wasn't found,
25-
// therefore it needs to be pulled
26-
logrus.Debugf("The image %s wasn't found locally", debugImage)
27-
return false, nil
28-
}
29-
30-
debugImageOs := debugImageInspect.Os
31-
debugImageArchitecture := debugImageInspect.Architecture
32-
// override through --platform flag
33-
if debugImagePlatform != "" {
34-
fmt.Sscanf(debugImagePlatform, "%s/%s", &debugImageOs, &debugImageArchitecture)
35-
}
36-
37-
// target.Platform only contains the Os but doesn't have the Arch, however we can
38-
// get the Os & Arch by analyzing the image using target.Image
39-
targetImageInspect, _, err := client.ImageInspectWithRaw(ctx, target.Image)
40-
if err != nil {
41-
return false, fmt.Errorf("failed to inspect image %s: %v", target.Image, err)
42-
}
43-
44-
// debug image exists, also check that the platform matches the target image platform
45-
if debugImageArchitecture != targetImageInspect.Architecture || debugImageOs != targetImageInspect.Os {
46-
return false, nil
47-
}
48-
49-
return true, nil
50-
}
51-
5220
func runDebuggerDocker(ctx context.Context, cli cliutil.CLI, opts *options) error {
5321
client, err := docker.NewClient(docker.Options{
5422
Out: cli.AuxStream(),
@@ -66,20 +34,19 @@ func runDebuggerDocker(ctx context.Context, cli cliutil.CLI, opts *options) erro
6634
return errTargetNotRunning
6735
}
6836

69-
imageExists, err := debugImageExistsLocally(ctx, client, opts.image, opts.platform, target)
37+
platform := opts.platform
38+
if len(platform) == 0 {
39+
platform = target.Platform
40+
}
41+
42+
imageExists, err := imageExistsLocally(ctx, client, opts.image, platform)
7043
if err != nil {
7144
return err
7245
}
73-
7446
if !imageExists {
7547
cli.PrintAux("Pulling debugger image...\n")
7648
if err := client.ImagePullEx(ctx, opts.image, types.ImagePullOptions{
77-
Platform: func() string {
78-
if len(opts.platform) == 0 {
79-
return target.Platform
80-
}
81-
return opts.platform
82-
}(),
49+
Platform: platform,
8350
}); err != nil {
8451
return errCannotPull(opts.image, err)
8552
}
@@ -265,3 +232,34 @@ func (s *ioStreamer) stream(ctx context.Context) error {
265232
func ptr[T any](v T) *T {
266233
return &v
267234
}
235+
236+
func imageExistsLocally(
237+
ctx context.Context,
238+
client *docker.Client,
239+
image string,
240+
platform string,
241+
) (bool, error) {
242+
imageSummary, _, err := client.ImageInspectWithRaw(ctx, image)
243+
if err != nil {
244+
logrus.Debugf("The image %s (%s) wasn't found locally", image, platform)
245+
return false, nil
246+
}
247+
248+
parts := strings.Split(platform, "/")
249+
if imageSummary.Os != parts[0] {
250+
logrus.Debugf("The image %s (%s) found locally, but the OS doesn't match", image, platform)
251+
return false, nil
252+
}
253+
254+
if len(parts) > 1 && imageSummary.Architecture != parts[1] {
255+
logrus.Debugf("The image %s (%s) found locally, but the architecture doesn't match", image, platform)
256+
return false, nil
257+
}
258+
259+
if len(parts) > 2 && imageSummary.Variant != parts[2] {
260+
logrus.Debugf("The image %s (%s) found locally, but the variant doesn't match", image, platform)
261+
return false, nil
262+
}
263+
264+
return true, nil
265+
}

e2e/exec/docker_test.go

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package exec
22

33
import (
4-
"fmt"
5-
"regexp"
4+
"strings"
65
"testing"
76

87
"gotest.tools/assert"
@@ -23,27 +22,6 @@ func TestExecDockerSimple(t *testing.T) {
2322
assert.Check(t, cmp.Contains(res.Stdout(), "debian"))
2423
}
2524

26-
func TestExecDockerUseLocalImage(t *testing.T) {
27-
localImage, cleanupLocalImage := fixture.DockerBuildLocalImage(t)
28-
defer cleanupLocalImage()
29-
30-
targetImageID, targetImageCleanup := fixture.DockerRunBackground(t, fixture.ImageNginx, nil)
31-
defer targetImageCleanup()
32-
33-
res := icmd.RunCmd(
34-
icmd.Command("cdebug", "--image", localImage, "-l=debug", "exec", "--rm", "-q", targetImageID, "cat", "/etc/os-release"),
35-
)
36-
res.Assert(t, icmd.Success)
37-
assert.Check(t, cmp.Contains(res.Stdout(), "debian"))
38-
assert.Assert(t, func() cmp.Result {
39-
re := regexp.MustCompile("Pulling debugger image...")
40-
if re.MatchString(res.Stdout()) {
41-
return cmp.ResultFailure(fmt.Sprintf("Image %s shouldn't be pulled because it only exists locally", localImage))
42-
}
43-
return cmp.ResultSuccess
44-
})
45-
}
46-
4725
func TestExecDockerHostNamespaces(t *testing.T) {
4826
targetID, cleanup := fixture.DockerRunBackground(t, fixture.ImageNginx,
4927
[]string{"--net", "host", "--pid", "host"},
@@ -90,3 +68,28 @@ func TestExecDockerNixery(t *testing.T) {
9068
res.Assert(t, icmd.Success)
9169
assert.Check(t, cmp.Contains(res.Stdout(), "VIM - Vi IMproved"))
9270
}
71+
72+
func TestExecDockerUseLocalImage(t *testing.T) {
73+
targetID, targetCleanup := fixture.DockerRunBackground(t, fixture.ImageNginx, nil)
74+
defer targetCleanup()
75+
76+
remoteImage := "busybox:musl"
77+
fixture.DockerImageRemove(t, remoteImage)
78+
79+
res := icmd.RunCmd(
80+
icmd.Command("cdebug", "exec", "--rm", "-i", "--image", remoteImage, targetID, "cat", "/etc/os-release"),
81+
)
82+
res.Assert(t, icmd.Success)
83+
assert.Check(t, cmp.Contains(res.Stdout(), "debian"))
84+
assert.Check(t, cmp.Contains(res.Stderr(), "Pulling debugger image..."))
85+
86+
localImage, imageCleanup := fixture.DockerImageBuild(t, "thisimageonlyexistslocally:1.0")
87+
defer imageCleanup()
88+
89+
res = icmd.RunCmd(
90+
icmd.Command("cdebug", "exec", "--rm", "-i", "--image", localImage, targetID, "cat", "/etc/os-release"),
91+
)
92+
res.Assert(t, icmd.Success)
93+
assert.Check(t, cmp.Contains(res.Stdout(), "debian"))
94+
assert.Equal(t, strings.Contains(res.Stderr(), "Pulling debugger image..."), false)
95+
}

e2e/internal/fixture/Dockerfile

Lines changed: 0 additions & 1 deletion
This file was deleted.

e2e/internal/fixture/fixture.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package fixture
22

33
import (
44
"os/exec"
5-
"path/filepath"
6-
"runtime"
75
"strings"
86
"testing"
97

@@ -91,28 +89,30 @@ func DockerRunBackground(
9189
return contID, cleanup
9290
}
9391

94-
func DockerBuildLocalImage(
92+
func DockerImageBuild(
9593
t *testing.T,
94+
name string,
9695
) (string, func()) {
97-
localImage := "thisimageonlyexistslocally:1.0"
96+
cmd := dockerCmd("build", "-t", name, "-")
9897

99-
// Get dirname of current file, assumes that the Dockerfile lives next to this file.
100-
_, filename, _, ok := runtime.Caller(0)
101-
if !ok {
102-
t.Fatalf("Failed to get filename")
103-
}
104-
dirname := filepath.Dir(filename)
105-
106-
cmd := dockerCmd("build", "-t", localImage, dirname)
107-
108-
res := icmd.RunCmd(cmd)
98+
res := icmd.RunCmd(cmd, icmd.WithStdin(strings.NewReader("FROM busybox:musl\n")))
10999
res.Assert(t, icmd.Success)
110100

111101
cleanup := func() {
112-
icmd.RunCmd(dockerCmd("rmi", localImage)).Assert(t, icmd.Success)
102+
icmd.RunCmd(dockerCmd("rmi", name)).Assert(t, icmd.Success)
113103
}
114104

115-
return localImage, cleanup
105+
return name, cleanup
106+
}
107+
108+
func DockerImageRemove(
109+
t *testing.T,
110+
name string,
111+
) {
112+
res := icmd.RunCmd(dockerCmd("rmi", name))
113+
if !strings.Contains(res.Stderr(), "No such image") {
114+
res.Assert(t, icmd.Success)
115+
}
116116
}
117117

118118
func NerdctlRunBackground(

0 commit comments

Comments
 (0)