Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasi: Support sharing envvar to container #118

Merged
merged 1 commit into from
Sep 2, 2023
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
2 changes: 2 additions & 0 deletions cmd/init/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ func patchSpec(s runtimespec.Spec, infoD []byte, imageConfig imagespec.Image) ru
args = append(args, strings.ReplaceAll(string(o[prev:]), "\\ ", " "))
case "e":
entrypoint = []string{o}
case "env":
s.Process.Env = append(s.Process.Env, o)
default:
log.Printf("unsupported prefix: %q", inst)
}
Expand Down
43 changes: 43 additions & 0 deletions patches/bochs/Bochs/bochs/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

#ifdef WASI
#include <wizer.h>
#include <wasi/libc-environ.h>
extern "C" {
#include "jmp.h"
}
Expand Down Expand Up @@ -382,6 +383,34 @@ int write_args(FSVirtFile *f, int argc, char **argv, int optind, int pos1)
return pos - pos1;
}

int write_env(FSVirtFile *f, int pos1, const char *env)
{
int p, pos = pos1;

p = write_info(f, pos, 5, "env: ");
if (p < 0) {
return -1;
}
pos += p;
for (int j = 0; j < strlen(env); j++) {
if (env[j] == '\n') {
p = write_info(f, pos, 2, "\\\n");
if (p != 2) {
return -1;
}
pos += p;
continue;
}
if (putchar_info(f, pos++, env[j]) != 1) {
return -1;
}
}
if (putchar_info(f, pos++, '\n') != 1) {
return -1;
}
return pos - pos1;
}

static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "no-stdin", no_argument },
Expand Down Expand Up @@ -465,6 +494,19 @@ int init_wasi_info(int argc, char **argv, FSVirtFile *info)
pos += p;
}

#ifdef WASI
// TODO: support emscripten; it seems some default variables are passed, which shouldn't be inherited by the container.
// https://github.com/emscripten-core/emscripten/blob/0566a76b500bd2bbd535e108f657fce1db7f6f75/src/library_wasi.js#L62
for (char **env = environ; *env; ++env) {
int p = write_env(info, pos, *env);
if (p < 0) {
printf("failed to prepare env info\n");
exit(1);
}
pos += p;
}
#endif

info->len = pos;
#ifdef WASI
info->len += write_preopen_info(info, pos);
Expand Down Expand Up @@ -752,6 +794,7 @@ int CDECL start_vm(void)
int CDECL main(int argc, char *argv[])
{
#ifdef WASI
__wasilibc_ensure_environ();
__wasi_vfs_rt_init();
if (populate_preopens() != 0) { // register wasi-vfs dir to wasi-libc and our list
fprintf(stderr, "failed to populate preopens");
Expand Down
43 changes: 43 additions & 0 deletions patches/tinyemu/tinyemu/temu.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
#include "wasi.h"
#endif

extern char **environ;

#ifdef ON_BROWSER
#include <emscripten.h>
#endif
Expand Down Expand Up @@ -918,6 +920,34 @@ int write_args(FSVirtFile *f, int argc, char **argv, int optind, int pos1)
return pos - pos1;
}

int write_env(FSVirtFile *f, int pos1, const char *env)
{
int p, pos = pos1;

p = write_info(f, pos, 5, "env: ");
if (p < 0) {
return -1;
}
pos += p;
for (int j = 0; j < strlen(env); j++) {
if (env[j] == '\n') {
p = write_info(f, pos, 2, "\\\n");
if (p != 2) {
return -1;
}
pos += p;
continue;
}
if (putchar_info(f, pos++, env[j]) != 1) {
return -1;
}
}
if (putchar_info(f, pos++, '\n') != 1) {
return -1;
}
return pos - pos1;
}

int main(int argc, char **argv)
{
#ifdef WASI
Expand Down Expand Up @@ -984,6 +1014,19 @@ int main(int argc, char **argv)
pos += p;
}

#ifdef WASI
// TODO: support emscripten; it seems some default variables are passed, which shouldn't be inherited by the container.
// https://github.com/emscripten-core/emscripten/blob/0566a76b500bd2bbd535e108f657fce1db7f6f75/src/library_wasi.js#L62
for (char **env = environ; *env; ++env) {
int p = write_env(info, pos, *env);
if (p < 0) {
printf("failed to prepare env info\n");
exit(1);
}
pos += p;
}
#endif

info->len = pos;
#ifdef WASI
info->len += write_preopen_info(info, pos);
Expand Down
2 changes: 2 additions & 0 deletions patches/tinyemu/tinyemu/wasi.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <string.h>

#include <wasi/libc.h>
#include <wasi/libc-environ.h>

#include "cutils.h"
#include "fs.h"
Expand Down Expand Up @@ -160,6 +161,7 @@ extern void __wasi_vfs_rt_init(void);

int init_wasi()
{
__wasilibc_ensure_environ();
__wasi_vfs_rt_init(); // initialize wasi-vfs
if (populate_preopens() != 0) { // register mapdir and wasi-vfs dir to wasi-libc and our list
fprintf(stderr, "failed to populate preopens");
Expand Down
15 changes: 15 additions & 0 deletions tests/integration/wamr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,20 @@ func TestWamr(t *testing.T) {
},
),
},
{
Name: "wamr-env",
Runtime: "iwasm",
Inputs: []utils.Input{
{Image: "alpine:3.17", Architecture: utils.X86_64},
{Image: "riscv64/alpine:20221110", ConvertOpts: []string{"--target-arch=riscv64"}, Architecture: utils.RISCV64},
},
ImageName: "test2.wasm",
Prepare: func(t *testing.T, workdir string) {
assert.NilError(t, exec.Command("wamrc", "-o", filepath.Join(workdir, "test2.wasm"), filepath.Join(workdir, "test.wasm")).Run())
},
RuntimeOpts: utils.StringFlags("--env=AAA=hello", "--env=BBB=world"),
Args: utils.StringFlags("/bin/sh", "-c", "echo -n $AAA $BBB"),
Want: utils.WantString("hello world"),
},
}...)
}
15 changes: 15 additions & 0 deletions tests/integration/wasmedge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,20 @@ func TestWasmedge(t *testing.T) {
Args: utils.StringFlags("--no-stdin", "cat", "/map/dir/hi"),
Want: utils.WantString("teststring"),
},
{
Name: "wasmedge-env",
Runtime: "wasmedge",
Inputs: []utils.Input{
{Image: "alpine:3.17", Architecture: utils.X86_64},
{Image: "riscv64/alpine:20221110", ConvertOpts: []string{"--target-arch=riscv64"}, Architecture: utils.RISCV64},
},
ImageName: "test2.wasm",
Prepare: func(t *testing.T, workdir string) {
assert.NilError(t, exec.Command("wasmedgec", filepath.Join(workdir, "test.wasm"), filepath.Join(workdir, "test2.wasm")).Run())
},
RuntimeOpts: utils.StringFlags("--env=AAA=hello", "--env=BBB=world"),
Args: utils.StringFlags("--no-stdin", "/bin/sh", "-c", "echo -n $AAA $BBB"), // NOTE: stdin unsupported on wasmedge as of now
Want: utils.WantString("hello world"),
},
}...)
}
11 changes: 11 additions & 0 deletions tests/integration/wasmer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,16 @@ func TestWasmer(t *testing.T) {
Args: utils.StringFlags("--", "--no-stdin", "cat", "/mapped/dir/test/hi"),
Want: utils.WantString("teststring"),
},
{
Name: "wasmer-env",
Runtime: "wasmer",
Inputs: []utils.Input{
{Image: "alpine:3.17", Architecture: utils.X86_64},
{Image: "riscv64/alpine:20221110", ConvertOpts: []string{"--target-arch=riscv64"}, Architecture: utils.RISCV64},
},
RuntimeOpts: utils.StringFlags("--env=AAA=hello", "--env=BBB=world"),
Args: utils.StringFlags("--", "--no-stdin", "/bin/sh", "-c", "echo -n $AAA $BBB"), // wasmer requires "--" before flags we pass to the wasm program.
Want: utils.WantString("hello world"),
},
}...)
}
11 changes: 11 additions & 0 deletions tests/integration/wasmtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ func TestWasmtime(t *testing.T) {
[2]string{"echo -n hello > /mapped/dir/test/from-guest/testhello\n", ""},
),
},
{
Name: "wasmtime-env",
Runtime: "wasmtime",
Inputs: []utils.Input{
{Image: "alpine:3.17", Architecture: utils.X86_64},
{Image: "riscv64/alpine:20221110", ConvertOpts: []string{"--target-arch=riscv64"}, Architecture: utils.RISCV64},
},
RuntimeOpts: utils.StringFlags("--env=AAA=hello", "--env=BBB=world"),
Args: utils.StringFlags("/bin/sh", "-c", "echo -n $AAA $BBB"),
Want: utils.WantString("hello world"),
},
// Other architectures
{
Name: "wasmtime-hello-arch-aarch64",
Expand Down
11 changes: 11 additions & 0 deletions tests/integration/wazero_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,16 @@ func TestWazero(t *testing.T) {
[2]string{"echo -n hello > /mapdir/from-guest/testhello\n", ""},
),
},
{
Name: "wazero-env",
Runtime: "wazero-test",
Inputs: []utils.Input{
{Image: "alpine:3.17", Architecture: utils.X86_64},
{Image: "riscv64/alpine:20221110", ConvertOpts: []string{"--target-arch=riscv64"}, Architecture: utils.RISCV64},
},
RuntimeOpts: utils.StringFlags("--env=AAA=hello", "--env=BBB=world"),
Args: utils.StringFlags("/bin/sh", "-c", "echo -n $AAA $BBB"),
Want: utils.WantString("hello world"),
},
}...)
}
26 changes: 23 additions & 3 deletions tests/wazero/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
crand "crypto/rand"
"flag"
"fmt"
"os"
"strings"

Expand All @@ -15,6 +16,8 @@ func main() {
var (
mapDir = flag.String("mapdir", "", "directory mapping to the image")
)
var envs envFlags
flag.Var(&envs, "env", "environment variables")

flag.Parse()
args := flag.Args()
Expand All @@ -41,11 +44,28 @@ func main() {
if err != nil {
panic(err)
}
// we forcibly enable non-blocking read of stdin.
_, err = r.InstantiateModule(ctx, compiled,
wazero.NewModuleConfig().WithSysWalltime().WithSysNanotime().WithSysNanosleep().WithRandSource(crand.Reader).WithStdout(os.Stdout).WithStderr(os.Stderr).WithStdin(os.Stdin).WithFSConfig(fsConfig).WithArgs(append([]string{"arg0"}, args[1:]...)...))
conf := wazero.NewModuleConfig().WithSysWalltime().WithSysNanotime().WithSysNanosleep().WithRandSource(crand.Reader).WithStdout(os.Stdout).WithStderr(os.Stderr).WithStdin(os.Stdin).WithFSConfig(fsConfig).WithArgs(append([]string{"arg0"}, args[1:]...)...)
for _, v := range envs {
es := strings.SplitN(v, "=", 2)
if len(es) == 2 {
conf = conf.WithEnv(es[0], es[1])
} else {
panic("env must be a key value pair")
}
}
_, err = r.InstantiateModule(ctx, compiled, conf)
if err != nil {
panic(err)
}
return
}

type envFlags []string

func (i *envFlags) String() string {
return fmt.Sprintf("%v", []string(*i))
}
func (i *envFlags) Set(value string) error {
*i = append(*i, value)
return nil
}