Add tests for $HOME

Adds two tests. One to make sure that $HOME is set when starting a container
via 'docker run' and one to make sure that $HOME is set for each container in a
multi-container sandbox.

Issue #701

PiperOrigin-RevId: 273395763
This commit is contained in:
Ian Lewis
2019-10-07 15:55:39 -07:00
committed by gVisor bot
parent 6a98237949
commit da9e18f24d
5 changed files with 165 additions and 20 deletions
+49 -18
View File
@@ -157,13 +157,55 @@ func (cc *Crictl) RmPod(podID string) error {
return err
}
// StartContainer pulls the given image ands starts the container in the
// sandbox with the given podID.
func (cc *Crictl) StartContainer(podID, image, sbSpec, contSpec string) (string, error) {
// Write the specs to files that can be read by crictl.
sbSpecFile, err := testutil.WriteTmpFile("sbSpec", sbSpec)
if err != nil {
return "", fmt.Errorf("failed to write sandbox spec: %v", err)
}
contSpecFile, err := testutil.WriteTmpFile("contSpec", contSpec)
if err != nil {
return "", fmt.Errorf("failed to write container spec: %v", err)
}
return cc.startContainer(podID, image, sbSpecFile, contSpecFile)
}
func (cc *Crictl) startContainer(podID, image, sbSpecFile, contSpecFile string) (string, error) {
if err := cc.Pull(image); err != nil {
return "", fmt.Errorf("failed to pull %s: %v", image, err)
}
contID, err := cc.Create(podID, contSpecFile, sbSpecFile)
if err != nil {
return "", fmt.Errorf("failed to create container in pod %q: %v", podID, err)
}
if _, err := cc.Start(contID); err != nil {
return "", fmt.Errorf("failed to start container %q in pod %q: %v", contID, podID, err)
}
return contID, nil
}
// StopContainer stops and deletes the container with the given container ID.
func (cc *Crictl) StopContainer(contID string) error {
if err := cc.Stop(contID); err != nil {
return fmt.Errorf("failed to stop container %q: %v", contID, err)
}
if err := cc.Rm(contID); err != nil {
return fmt.Errorf("failed to remove container %q: %v", contID, err)
}
return nil
}
// StartPodAndContainer pulls an image, then starts a sandbox and container in
// that sandbox. It returns the pod ID and container ID.
func (cc *Crictl) StartPodAndContainer(image, sbSpec, contSpec string) (string, string, error) {
if err := cc.Pull(image); err != nil {
return "", "", fmt.Errorf("failed to pull %s: %v", image, err)
}
// Write the specs to files that can be read by crictl.
sbSpecFile, err := testutil.WriteTmpFile("sbSpec", sbSpec)
if err != nil {
@@ -179,28 +221,17 @@ func (cc *Crictl) StartPodAndContainer(image, sbSpec, contSpec string) (string,
return "", "", err
}
contID, err := cc.Create(podID, contSpecFile, sbSpecFile)
if err != nil {
return "", "", fmt.Errorf("failed to create container in pod %q: %v", podID, err)
}
contID, err := cc.startContainer(podID, image, sbSpecFile, contSpecFile)
if _, err := cc.Start(contID); err != nil {
return "", "", fmt.Errorf("failed to start container %q in pod %q: %v", contID, podID, err)
}
return podID, contID, nil
return podID, contID, err
}
// StopPodAndContainer stops a container and pod.
func (cc *Crictl) StopPodAndContainer(podID, contID string) error {
if err := cc.Stop(contID); err != nil {
if err := cc.StopContainer(contID); err != nil {
return fmt.Errorf("failed to stop container %q in pod %q: %v", contID, podID, err)
}
if err := cc.Rm(contID); err != nil {
return fmt.Errorf("failed to remove container %q in pod %q: %v", contID, podID, err)
}
if err := cc.StopPod(podID); err != nil {
return fmt.Errorf("failed to stop pod %q: %v", podID, err)
}
+21 -2
View File
@@ -208,8 +208,27 @@ func TestExecEnv(t *testing.T) {
if err != nil {
t.Fatalf("docker exec failed: %v", err)
}
if want := "BAR"; !strings.Contains(got, want) {
t.Errorf("wanted exec output to contain %q, got %q", want, got)
if got, want := strings.TrimSpace(got), "BAR"; got != want {
t.Errorf("bad output from 'docker exec'. Got %q; Want %q.", got, want)
}
}
// TestRunEnvHasHome tests that run always has HOME environment set.
func TestRunEnvHasHome(t *testing.T) {
// Base alpine image does not have any environment variables set.
if err := dockerutil.Pull("alpine"); err != nil {
t.Fatalf("docker pull failed: %v", err)
}
d := dockerutil.MakeDocker("run-env-test")
// Exec "echo $HOME". The 'bin' user's home dir is '/bin'.
got, err := d.RunFg("--user", "bin", "alpine", "/bin/sh", "-c", "echo $HOME")
if err != nil {
t.Fatalf("docker run failed: %v", err)
}
defer d.CleanUp()
if got, want := strings.TrimSpace(got), "/bin"; got != want {
t.Errorf("bad output from 'docker run'. Got %q; Want %q.", got, want)
}
}
+53
View File
@@ -126,6 +126,59 @@ func TestMountOverSymlinks(t *testing.T) {
}
}
// TestHomeDir tests that the HOME environment variable is set for
// multi-containers.
func TestHomeDir(t *testing.T) {
// Setup containerd and crictl.
crictl, cleanup, err := setup(t)
if err != nil {
t.Fatalf("failed to setup crictl: %v", err)
}
defer cleanup()
contSpec := testdata.SimpleSpec("root", "k8s.gcr.io/busybox", []string{"sleep", "1000"})
podID, contID, err := crictl.StartPodAndContainer("k8s.gcr.io/busybox", testdata.Sandbox, contSpec)
if err != nil {
t.Fatal(err)
}
t.Run("root container", func(t *testing.T) {
out, err := crictl.Exec(contID, "sh", "-c", "echo $HOME")
if err != nil {
t.Fatal(err)
}
if got, want := strings.TrimSpace(string(out)), "/root"; got != want {
t.Fatalf("Home directory invalid. Got %q, Want : %q", got, want)
}
})
t.Run("sub-container", func(t *testing.T) {
// Create a sub container in the same pod.
subContSpec := testdata.SimpleSpec("subcontainer", "k8s.gcr.io/busybox", []string{"sleep", "1000"})
subContID, err := crictl.StartContainer(podID, "k8s.gcr.io/busybox", testdata.Sandbox, subContSpec)
if err != nil {
t.Fatal(err)
}
out, err := crictl.Exec(subContID, "sh", "-c", "echo $HOME")
if err != nil {
t.Fatal(err)
}
if got, want := strings.TrimSpace(string(out)), "/root"; got != want {
t.Fatalf("Home directory invalid. Got %q, Want: %q", got, want)
}
if err := crictl.StopContainer(subContID); err != nil {
t.Fatal(err)
}
})
// Stop everything.
if err := crictl.StopPodAndContainer(podID, contID); err != nil {
t.Fatal(err)
}
}
// setup sets up before a test. Specifically it:
// * Creates directories and a socket for containerd to utilize.
// * Runs containerd and waits for it to reach a "ready" state for testing.
+1
View File
@@ -10,6 +10,7 @@ go_library(
"httpd.go",
"httpd_mount_paths.go",
"sandbox.go",
"simple.go",
],
importpath = "gvisor.dev/gvisor/test/root/testdata",
visibility = [
+41
View File
@@ -0,0 +1,41 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package testdata
import (
"encoding/json"
"fmt"
)
// SimpleSpec returns a JSON config for a simple container that runs the
// specified command in the specified image.
func SimpleSpec(name, image string, cmd []string) string {
cmds, err := json.Marshal(cmd)
if err != nil {
// This shouldn't happen.
panic(err)
}
return fmt.Sprintf(`
{
"metadata": {
"name": %q
},
"image": {
"image": %q
},
"command": %s
}
`, name, image, cmds)
}