Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions pkg/driver/microsandbox/cliclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (c cliClient) Create(ctx context.Context, sandbox string, spec sandboxSpec)
if err := c.ensureVolumes(ctx, spec.Mounts); err != nil {
return err
}
return msbRun(ctx, createArgs(sandbox, spec)...)
return msbRun(ctx, runArgs(sandbox, spec)...)
}

func (cliClient) Find(ctx context.Context, sandbox string) (*sandboxInfo, error) {
Expand Down Expand Up @@ -150,19 +150,32 @@ func (cliClient) ensureVolumes(ctx context.Context, mounts []volumeMount) error
return nil
}

func createArgs(sandbox string, spec sandboxSpec) []string {
args := []string{names.Create, names.Flag(names.Name), sandbox}
const (
msbCmdRun = "run"
msbFlagDetach = "--detach"
)

// runArgs builds a detached `msb run` invocation, matching microsandbox's own
// ENTRYPOINT/CMD split: --entrypoint sets the executable, and a trailing "--"
// plus argv overrides the image CMD.
func runArgs(sandbox string, spec sandboxSpec) []string {
args := []string{msbCmdRun, msbFlagDetach, names.Flag(names.Name), sandbox}
if spec.Entrypoint != "" {
args = append(args, "--entrypoint", spec.Entrypoint)
}
args = append(args, runtimeArgs(spec)...)
args = append(args, resourceArgs(spec)...)
args = append(args, mountArgs(spec.Mounts)...)
return append(args, spec.Image)
args = append(args, spec.Image)
if len(spec.Cmd) > 0 {
args = append(args, "--")
args = append(args, spec.Cmd...)
}
return args
}

func runtimeArgs(spec sandboxSpec) []string {
var args []string
if len(spec.Entrypoint) > 0 {
args = append(args, "--entrypoint", strings.Join(spec.Entrypoint, " "))
}
for k, v := range spec.Env {
args = append(args, names.Flag(names.Env), k+"="+v)
}
Expand Down
60 changes: 44 additions & 16 deletions pkg/driver/microsandbox/cliclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ import (
"github.com/devsy-org/devsy/pkg/flags/names"
)

func TestCreateArgsFull(t *testing.T) {
func runPrefix() []string {
return []string{msbCmdRun, msbFlagDetach, names.Flag(names.Name), wsName}
}

func TestRunArgsFull(t *testing.T) {
spec := sandboxSpec{
Image: testImg,
Entrypoint: []string{shPath, "-c", "sleep infinity"},
Entrypoint: shPath,
Cmd: []string{"-c", "sleep infinity", "-"},
Env: map[string]string{"K": "v"},
Labels: map[string]string{"devsy.sh/user": "vscode"},
IdleTimeout: 90 * time.Second,
Expand All @@ -26,18 +31,23 @@ func TestCreateArgsFull(t *testing.T) {
{Target: "/tmp", Tmpfs: true},
},
}
args := createArgs(wsName, spec)
args := runArgs(wsName, spec)

if !slices.Equal(args[:4], runPrefix()) {
t.Errorf("prefix = %v, want %v", args[:4], runPrefix())
}

// name comes first, image last.
if args[0] != names.Create || args[1] != names.Flag(names.Name) || args[2] != wsName {
t.Errorf("prefix = %v", args[:3])
imgIdx := slices.Index(args, testImg)
if imgIdx < 0 {
t.Fatalf("image not found in %v", args)
}
if args[len(args)-1] != testImg {
t.Errorf("image should be the final arg, got %q", args[len(args)-1])
wantSuffix := append([]string{testImg, "--"}, spec.Cmd...)
if !slices.Equal(args[imgIdx:], wantSuffix) {
t.Errorf("image+cmd suffix = %v, want %v", args[imgIdx:], wantSuffix)
}

want := [][2]string{
{"--entrypoint", "/bin/sh -c sleep infinity"},
wantFlags := [][2]string{
{"--entrypoint", shPath},
{names.Flag(names.Env), "K=v"},
{"--label", "devsy.sh/user=vscode"},
{"--idle-timeout", "1m30s"},
Expand All @@ -48,20 +58,38 @@ func TestCreateArgsFull(t *testing.T) {
{"--mount-named", "cache-vol:/cache"},
{"--tmpfs", "/tmp"},
}
for _, kv := range want {
for _, kv := range wantFlags {
if !hasFlagValue(args, kv[0], kv[1]) {
t.Errorf("missing %s %q in %v", kv[0], kv[1], args)
}
}
if hasFlag(args, "--net-default-egress") == false {
if !hasFlag(args, "--net-default-egress") {
t.Errorf("expected egress deny flag in %v", args)
}
}

func TestCreateArgsMinimal(t *testing.T) {
args := createArgs(wsName, sandboxSpec{Image: testImg})
// Only name + image; no sizing/runtime flags for a bare spec.
want := []string{names.Create, names.Flag(names.Name), wsName, testImg}
func TestRunArgsMinimal(t *testing.T) {
args := runArgs(wsName, sandboxSpec{Image: testImg})
want := append(runPrefix(), testImg)
if !slices.Equal(args, want) {
t.Errorf("args = %v, want %v", args, want)
}
}

func TestRunArgsCmdWithoutEntrypoint(t *testing.T) {
args := runArgs(wsName, sandboxSpec{Image: testImg, Cmd: []string{"python3", "worker.py"}})
if hasFlag(args, "--entrypoint") {
t.Errorf("did not expect --entrypoint in %v", args)
}
want := append(runPrefix(), testImg, "--", "python3", "worker.py")
if !slices.Equal(args, want) {
t.Errorf("args = %v, want %v", args, want)
}
}

func TestRunArgsEntrypointWithoutCmd(t *testing.T) {
args := runArgs(wsName, sandboxSpec{Image: testImg, Entrypoint: shPath})
want := append(runPrefix(), "--entrypoint", shPath, testImg)
if !slices.Equal(args, want) {
t.Errorf("args = %v, want %v", args, want)
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/driver/microsandbox/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (

type sandboxSpec struct {
Image string
Entrypoint []string
Entrypoint string
Cmd []string
Memory uint32
CPUs uint8
Env map[string]string
Expand Down
11 changes: 2 additions & 9 deletions pkg/driver/microsandbox/microsandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,8 @@ func (d *microsandboxDriver) buildSpec(workspaceID string, options *driver.RunOp
}
return sandboxSpec{
Image: options.Image,
Entrypoint: entrypointArgv(options),
Entrypoint: options.Entrypoint,
Cmd: options.Cmd,
Memory: d.defaults.memory,
CPUs: d.defaults.cpus,
Env: options.Env,
Expand Down Expand Up @@ -437,14 +438,6 @@ func hasUserNSMapping(options *driver.RunOptions) bool {
return options.Userns != "" || len(options.UidMap) > 0 || len(options.GidMap) > 0
}

func entrypointArgv(options *driver.RunOptions) []string {
var argv []string
if options.Entrypoint != "" {
argv = append(argv, options.Entrypoint)
}
return append(argv, options.Cmd...)
}

func toContainerDetails(info *sandboxInfo) *config.ContainerDetails {
status := "exited"
if info.Running {
Expand Down
16 changes: 7 additions & 9 deletions pkg/driver/microsandbox/microsandbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,15 +365,13 @@ func TestRunDevContainerSetsEntrypoint(t *testing.T) {
if err != nil {
t.Fatalf("RunDevContainer: %v", err)
}
got := f.created[wsName].Entrypoint
want := []string{shPath, "-c", "start", "-"}
if len(got) != len(want) {
t.Fatalf("entrypoint = %v, want %v", got, want)
}
for i := range want {
if got[i] != want[i] {
t.Fatalf("entrypoint = %v, want %v", got, want)
}
got := f.created[wsName]
if got.Entrypoint != shPath {
t.Errorf("entrypoint = %q, want %q", got.Entrypoint, shPath)
}
want := []string{"-c", "start", "-"}
if !slices.Equal(got.Cmd, want) {
t.Errorf("cmd = %v, want %v", got.Cmd, want)
}
}

Expand Down
Loading