Skip to content

Commit

Permalink
snap: support "command: foo $ENV_STRING"
Browse files Browse the repository at this point in the history
  • Loading branch information
mvo5 committed Sep 30, 2017
1 parent f96badd commit 5637186
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 13 deletions.
30 changes: 24 additions & 6 deletions cmd/snap-exec/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,34 @@ func snapExecApp(snapApp, revision, command string, args []string) error {
if err != nil {
return err
}
// strings.Split() is ok here because we validate all app fields
// and the whitelist is pretty strict (see
// snap/validate.go:appContentWhitelist)
cmdArgv := strings.Split(cmdAndArgs, " ")
cmd := cmdArgv[0]
cmdArgs := cmdArgv[1:]

// build the environment from the yaml
env := append(os.Environ(), osutil.SubstituteEnv(app.Env())...)

// strings.Split() is ok here because we validate all app fields
// and the whitelist is pretty strict (see
// snap/validate.go:appContentWhitelist)
tmpCmdArgv := strings.Split(cmdAndArgs, " ")
cmd := tmpCmdArgv[0]

cmdArgs := make([]string, 0, len(tmpCmdArgv[1:]))
for _, arg := range tmpCmdArgv[1:] {
maybeExpanded := os.Expand(arg, func(k string) string {
for _, kv := range env {
l := strings.SplitN(kv, "=", 2)
if len(l) == 2 {
if k == l[0] {
return l[1]
}
}
}
return ""
})
if maybeExpanded != "" {
cmdArgs = append(cmdArgs, maybeExpanded)
}
}

// run the command
fullCmd := filepath.Join(app.Snap.MountDir(), cmd)
switch command {
Expand Down
34 changes: 32 additions & 2 deletions cmd/snap-exec/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ var mockYaml = []byte(`name: snapname
version: 1.0
apps:
app:
command: run-app cmd-arg1
command: run-app cmd-arg1 $SNAP_DATA
stop-command: stop-app
post-stop-command: post-stop-app
environment:
Expand Down Expand Up @@ -104,7 +104,7 @@ func (s *snapExecSuite) TestFindCommand(c *C) {
cmd string
expected string
}{
{cmd: "", expected: `run-app cmd-arg1`},
{cmd: "", expected: `run-app cmd-arg1 $SNAP_DATA`},
{cmd: "stop", expected: "stop-app"},
{cmd: "post-stop", expected: "post-stop-app"},
} {
Expand Down Expand Up @@ -313,3 +313,33 @@ func (s *snapExecSuite) TestSnapExecShellIntegration(c *C) {
c.Check(execArgs, DeepEquals, []string{execArgv0, "-c", "echo foo"})
c.Check(execEnv, testutil.Contains, "LD_LIBRARY_PATH=/some/path/lib")
}

func (s *snapExecSuite) TestSnapExecAppIntegrationWithVars(c *C) {
dirs.SetRootDir(c.MkDir())
snaptest.MockSnap(c, string(mockYaml), string(mockContents), &snap.SideInfo{
Revision: snap.R("42"),
})

execArgv0 := ""
execArgs := []string{}
execEnv := []string{}
syscallExec = func(argv0 string, argv []string, env []string) error {
execArgv0 = argv0
execArgs = argv
execEnv = env
return nil
}

// setup env
os.Setenv("SNAP_DATA", "/var/snap/snapname/42")
defer os.Unsetenv("SNAP_DATA")

// launch and verify its run the right way
err := snapExecApp("snapname.app", "42", "", []string{"user-arg1"})
c.Assert(err, IsNil)
c.Check(execArgv0, Equals, fmt.Sprintf("%s/snapname/42/run-app", dirs.SnapMountDir))
c.Check(execArgs, DeepEquals, []string{execArgv0, "cmd-arg1", "/var/snap/snapname/42", "user-arg1"})
c.Check(execEnv, testutil.Contains, "BASE_PATH=/some/path")
c.Check(execEnv, testutil.Contains, "LD_LIBRARY_PATH=/some/path/lib")
c.Check(execEnv, testutil.Contains, fmt.Sprintf("MY_PATH=%s", os.Getenv("PATH")))
}
2 changes: 1 addition & 1 deletion snap/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func validateField(name, cont string, whitelist *regexp.Regexp) error {

// appContentWhitelist is the whitelist of legal chars in the "apps"
// section of snap.yaml
var appContentWhitelist = regexp.MustCompile(`^[A-Za-z0-9/. _#:-]*$`)
var appContentWhitelist = regexp.MustCompile(`^[A-Za-z0-9/. _#:$-]*$`)
var validAppName = regexp.MustCompile("^[a-zA-Z0-9](?:-?[a-zA-Z0-9])*$")

// ValidateApp verifies the content in the app info.
Expand Down
8 changes: 7 additions & 1 deletion snap/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ func (s *ValidateSuite) TestAppWhitelistSimple(c *C) {
c.Check(ValidateApp(&AppInfo{Name: "foo", PostStopCommand: "foo"}), IsNil)
}

func (s *ValidateSuite) TestAppWhitelistWithVars(c *C) {
c.Check(ValidateApp(&AppInfo{Name: "foo", Command: "foo $SNAP_DATA"}), IsNil)
c.Check(ValidateApp(&AppInfo{Name: "foo", StopCommand: "foo $SNAP_DATA"}), IsNil)
c.Check(ValidateApp(&AppInfo{Name: "foo", PostStopCommand: "foo $SNAP_DATA"}), IsNil)
}

func (s *ValidateSuite) TestAppWhitelistIllegal(c *C) {
c.Check(ValidateApp(&AppInfo{Name: "x\n"}), NotNil)
c.Check(ValidateApp(&AppInfo{Name: "test!me"}), NotNil)
Expand Down Expand Up @@ -190,7 +196,7 @@ func (s *ValidateSuite) TestAppDaemonValue(c *C) {
func (s *ValidateSuite) TestAppWhitelistError(c *C) {
err := ValidateApp(&AppInfo{Name: "foo", Command: "x\n"})
c.Assert(err, NotNil)
c.Check(err.Error(), Equals, `app description field 'command' contains illegal "x\n" (legal: '^[A-Za-z0-9/. _#:-]*$')`)
c.Check(err.Error(), Equals, `app description field 'command' contains illegal "x\n" (legal: '^[A-Za-z0-9/. _#:$-]*$')`)
}

// Validate
Expand Down
6 changes: 6 additions & 0 deletions tests/lib/snaps/basic-run/meta/snap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: basic-run
version: 1.0
apps:
echo-data:
command: echo $SNAP_DATA

3 changes: 0 additions & 3 deletions tests/main/snap-run-hook/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ prepare: |
restore: |
rm basic-hooks_1.0_all.snap
restore: |
rm basic-hooks_1.0_all.snap
execute: |
# Note that `snap run` doesn't exit non-zero if the hook is missing, so we
# check the output instead.
Expand Down
12 changes: 12 additions & 0 deletions tests/main/snap-run/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
summary: Check that `snap run` runs

prepare: |
. $TESTSLIB/snaps.sh
install_local "$TESTSLIB/snaps/basic-run"
restore: |
rm basic-run_1.0_all.snap
execute: |
echo "Test that snap run use environments"
basic-run.echo | MATCH ^/var/snap

0 comments on commit 5637186

Please sign in to comment.