// TestProcFSRestrictions checks that access to sensitive paths under // /proc and /sys is correctly restricted: // https://github.com/coreos/rkt/issues/2484 func TestProcFSRestrictions(t *testing.T) { // check access to read-only paths roEntry := "/proc/sysrq-trigger" testContent := "h" roImage := patchTestACI("rkt-inspect-write-procfs.aci", fmt.Sprintf("--exec=/inspect --write-file --file-name %s --content %s", roEntry, testContent)) defer os.Remove(roImage) roCtx := testutils.NewRktRunCtx() defer roCtx.Cleanup() roCmd := fmt.Sprintf("%s --insecure-options=image run %s", roCtx.Cmd(), roImage) roExpectedLine := fmt.Sprintf("Cannot write to file \"%s\"", roEntry) runRktAndCheckOutput(t, roCmd, roExpectedLine, true) // check access to inaccessible paths hiddenEntry := "/sys/firmware/" hiddenImage := patchTestACI("rkt-inspect-stat-procfs.aci", fmt.Sprintf("--exec=/inspect --stat-file --file-name %s", hiddenEntry)) defer os.Remove(hiddenImage) hiddenCtx := testutils.NewRktRunCtx() defer hiddenCtx.Cleanup() hiddenCmd := fmt.Sprintf("%s --insecure-options=image run %s", hiddenCtx.Cmd(), hiddenImage) hiddenExpectedLine := fmt.Sprintf("%s: mode: d---------", hiddenEntry) runRktAndCheckOutput(t, hiddenCmd, hiddenExpectedLine, false) }
func testFetchNoStore(t *testing.T, args string, image string, imageArgs string, finalURL string) { remoteFetchMsgTpl := `remote fetching from URL %q` remoteFetchMsg := fmt.Sprintf(remoteFetchMsgTpl, finalURL) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() if _, err := importImageAndFetchHash(t, ctx, "", image); err != nil { t.Skip(fmt.Sprintf("%v, probably a network failure. Skipping...", err)) } cmd := fmt.Sprintf("%s --no-store %s %s %s", ctx.Cmd(), args, image, imageArgs) // 1. Run cmd with the image available in the store, should get $remoteFetchMsg. err := runRktAndCheckRegexOutput(t, cmd, remoteFetchMsg) status, _ := common.GetExitStatus(err) if status != 0 { t.Logf("%v", err) t.Skip("remote fetching failed, probably a network failure. Skipping...") } if err != nil { t.Fatalf("%q should be found: %v", remoteFetchMsg, err) } }
func testFetchDefault(t *testing.T, arg string, image string, imageArgs string, finalURL string) { remoteFetchMsgTpl := `remote fetching from URL %q` storeMsgTpl := `using image from local store for .* %s` if finalURL == "" { finalURL = image } remoteFetchMsg := fmt.Sprintf(remoteFetchMsgTpl, finalURL) storeMsg := fmt.Sprintf(storeMsgTpl, image) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() cmd := fmt.Sprintf("%s %s %s %s", ctx.Cmd(), arg, image, imageArgs) // 1. Run cmd with the image not available in the store, should get $remoteFetchMsg. err := runRktAndCheckRegexOutput(t, cmd, remoteFetchMsg) status, _ := common.GetExitStatus(err) if status != 0 { t.Logf("%v", err) t.Skip("remote fetching failed, probably a network failure. Skipping...") } // 2. Run cmd with the image available in the store, should get $storeMsg. runRktAndCheckRegexOutput(t, cmd, storeMsg) }
// Check that "enter" is able to wait for the ppid file to be created func TestPidFileDelayedStart(t *testing.T) { sleepImage := patchTestACI("rkt-inspect-sleep.aci", "--exec=/inspect --read-stdin") defer os.Remove(sleepImage) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() runChild, enterChild, pidFileName, pidFileNameBackup := preparePidFileRace(t, ctx, sleepImage) // Restore ppid file so the "enter" command can find it if err := os.Rename(pidFileNameBackup, pidFileName); err != nil { t.Fatalf("Cannot restore ppid file: %v", err) } // Now the "enter" command works and can complete if err := expectWithOutput(enterChild, "RktEnterWorksFine"); err != nil { t.Fatalf("Waited for enter to works but failed: %v", err) } if err := enterChild.Wait(); err != nil { t.Fatalf("rkt enter didn't terminate correctly: %v", err) } // Terminate the pod if err := runChild.SendLine("Bye"); err != nil { t.Fatalf("rkt couldn't write to the container: %v", err) } if err := expectWithOutput(runChild, "Received text: Bye"); err != nil { t.Fatalf("Expected Bye but not found: %v", err) } if err := runChild.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } }
// Check that "enter" doesn't wait forever for the ppid file when the pod is terminated func TestPidFileAbortedStart(t *testing.T) { sleepImage := patchTestACI("rkt-inspect-sleep.aci", "--exec=/inspect --read-stdin") defer os.Remove(sleepImage) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() runChild, enterChild, _, _ := preparePidFileRace(t, ctx, sleepImage) // Terminate the pod with the escape sequence: ^]^]^] if err := runChild.SendLine("\035\035\035"); err != nil { t.Fatalf("Failed to terminate the pod: %v", err) } waitOrFail(t, runChild, 1) // Now the "enter" command terminates quickly before := time.Now() if err := enterChild.Wait(); err.Error() != "exit status 1" { t.Fatalf("rkt enter didn't terminate as expected: %v", err) } delay := time.Now().Sub(before) t.Logf("rkt enter terminated %v after the pod was terminated", delay) if delay > time.Second { // 1 second shall be enough: it takes less than 50ms on my computer t.Fatalf("rkt enter didn't terminate quickly enough: %v", delay) } }
func TestAceValidator(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() if err := ctx.LaunchMDS(); err != nil { t.Fatalf("Cannot launch metadata service: %v", err) } aceMain := os.Getenv("RKT_ACE_MAIN_IMAGE") if aceMain == "" { panic("empty RKT_ACE_MAIN_IMAGE env var") } aceSidekick := os.Getenv("RKT_ACE_SIDEKICK_IMAGE") if aceSidekick == "" { panic("empty RKT_ACE_SIDEKICK_IMAGE env var") } rktArgs := fmt.Sprintf("--debug --insecure-skip-verify run --mds-register --volume database,kind=empty %s %s", aceMain, aceSidekick) rktCmd := fmt.Sprintf("%s %s", ctx.Cmd(), rktArgs) child := spawnOrFail(t, rktCmd) defer waitOrFail(t, child, true) for _, e := range expectedResults { if err := expectWithOutput(child, e); err != nil { t.Fatalf("Expected %q but not found: %v", e, err) } } }
func TestAPIServiceGetInfo(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() svc := startAPIService(t, ctx) defer stopAPIService(t, svc) c, conn := newAPIClientOrFail(t, "localhost:15441") defer conn.Close() resp, err := c.GetInfo(context.Background(), &v1alpha.GetInfoRequest{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } expectedAPIVersion := "1.0.0-alpha" if resp.Info.ApiVersion != expectedAPIVersion { t.Errorf("Expected api version to be %q, but saw %q", expectedAPIVersion, resp.Info.ApiVersion) } expectedGlobalFlags := &v1alpha.GlobalFlags{ Dir: ctx.DataDir(), SystemConfigDir: ctx.SystemDir(), LocalConfigDir: ctx.LocalDir(), UserConfigDir: ctx.UserDir(), InsecureFlags: "none", } if !reflect.DeepEqual(resp.Info.GlobalFlags, expectedGlobalFlags) { t.Errorf("Expected global flags to be %v, but saw %v", expectedGlobalFlags, resp.Info.GlobalFlags) } }
func TestAuthSanity(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() server := runServer(t, taas.None) defer server.Close() expectedRunRkt(ctx, t, server.URL, "sanity", authSuccessfulDownload) }
// TestHostname test that the --hostname option works. func TestHostname(t *testing.T) { imageFile := patchTestACI("rkt-inspect-hostname.aci", "--exec=/inspect --print-hostname") defer os.Remove(imageFile) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() tests := []struct { hostname string }{ { "test-hostname", }, { "", }, } for _, tt := range tests { rktCmd := fmt.Sprintf("%s prepare --insecure-options=image %s", ctx.Cmd(), imageFile) uuid := runRktAndGetUUID(t, rktCmd) expectedHostname := "rkt-" + uuid hostnameParam := "" if tt.hostname != "" { expectedHostname = tt.hostname hostnameParam = fmt.Sprintf("--hostname=%s", tt.hostname) } rktCmd = fmt.Sprintf("%s run-prepared %s %s", ctx.Cmd(), hostnameParam, uuid) expected := fmt.Sprintf("Hostname: %s", expectedHostname) runRktAndCheckOutput(t, rktCmd, expected, false) } }
func TestAuthOverride(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() server, image := runAuthServer(t, taas.AuthOauth) defer authCleanup(server, image) hash := "sha512-" + getHashOrPanic(image) tests := []struct { systemConfig string localConfig string name string resultBeforeOverride string resultAfterOverride string }{ {server.Conf, getInvalidOAuthConfig(server.Conf), "valid-system-invalid-local", authSuccessfulDownload, authFailedDownload}, {getInvalidOAuthConfig(server.Conf), server.Conf, "invalid-system-valid-local", authFailedDownload, authSuccessfulDownload}, } for _, tt := range tests { writeConfig(t, authDir(ctx.SystemDir()), "test.json", tt.systemConfig) expectedRunRkt(ctx, t, server.URL, tt.name+"-1", tt.resultBeforeOverride) if tt.resultBeforeOverride == authSuccessfulDownload { // Remove the image from the store since it was fetched in the // previous run and the test aci-server returns a // Cache-Control max-age header removeFromCas(t, ctx, hash) } writeConfig(t, authDir(ctx.LocalDir()), "test.json", tt.localConfig) expectedRunRkt(ctx, t, server.URL, tt.name+"-2", tt.resultAfterOverride) ctx.Reset() } }
// TestPathsStat checks that access to inaccessible paths under // /proc or /sys is correctly restricted: // https://github.com/coreos/rkt/issues/2484 func TestPathsStat(t *testing.T) { tests := []struct { Path string ExpectedMode string }{ { Path: "/sys/firmware", ExpectedMode: "d---------", }, { Path: "/proc/kcore", ExpectedMode: "----------", }, } for _, tt := range tests { hiddenImage := patchTestACI("rkt-inspect-stat-procfs.aci", fmt.Sprintf("--exec=/inspect --stat-file --file-name %s", tt.Path)) defer os.Remove(hiddenImage) hiddenCtx := testutils.NewRktRunCtx() defer hiddenCtx.Cleanup() //run hiddenCmd := fmt.Sprintf("%s --debug --insecure-options=image run %s", hiddenCtx.Cmd(), hiddenImage) hiddenExpectedLine := fmt.Sprintf("%s: mode: %s", tt.Path, tt.ExpectedMode) runRktAndCheckOutput(t, hiddenCmd, hiddenExpectedLine, false) // run-prepared hiddenCmd = fmt.Sprintf(`%s --insecure-options=image prepare %s`, hiddenCtx.Cmd(), hiddenImage) uuid := runRktAndGetUUID(t, hiddenCmd) hiddenCmd = fmt.Sprintf("%s --debug run-prepared --mds-register=false %s", hiddenCtx.Cmd(), uuid) runRktAndCheckOutput(t, hiddenCmd, hiddenExpectedLine, false) } }
// TestHostDNS checks that --dns=host reflects the host's /etc/resolv.conf func TestDNSHost(t *testing.T) { dat, err := ioutil.ReadFile("/etc/resolv.conf") if err != nil { t.Fatal("Could not read host's resolv.conf", err) } sum := fmt.Sprintf("%x", sha1.Sum(dat)) t.Log("Expecting sum", sum) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() appCmd := "--exec=/inspect -- --hash-file" rktCmd := fmt.Sprintf("%s --insecure-options=image run --dns=host --set-env=FILE=/etc/resolv.conf %s %s", ctx.Cmd(), getInspectImagePath(), appCmd) child := spawnOrFail(t, rktCmd) ctx.RegisterChild(child) defer waitOrFail(t, child, 0) expectedRegex := `sha1sum: ([0-9a-f]+)` result, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second) if err != nil { t.Fatalf("Error: %v\nOutput: %v", err, out) } if result[1] != sum { t.Fatalf("container's /etc/host has sha1sum %s expected %s", result[1], sum) } }
func testFetchNoStore(t *testing.T, args string, image string, imageArgs string, finalURL string) { remoteFetchMsgTpl := `remote fetching from URL %q` remoteFetchMsg := fmt.Sprintf(remoteFetchMsgTpl, finalURL) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() if _, err := importImageAndFetchHash(t, ctx, "", image); err != nil { t.Skip(fmt.Sprintf("%v, probably a network failure. Skipping...", err)) } cmd := fmt.Sprintf("%s --no-store %s %s %s", ctx.Cmd(), args, image, imageArgs) // 1. Run cmd with the image available in the store, should get $remoteFetchMsg. child := spawnOrFail(t, cmd) if err := expectWithOutput(child, remoteFetchMsg); err != nil { t.Fatalf("%q should be found: %v", remoteFetchMsg, err) } err := child.Wait() status := getExitStatus(err) if status != 0 { t.Logf("rkt terminated with unexpected status %d, expected %d\nOutput:\n%s", status, 0, child.Collect()) t.Skip("remote fetching failed, probably a network failure. Skipping...") } }
func TestRmCgroup(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() imagePath := getInspectImagePath() cmd := fmt.Sprintf("%s --insecure-options=image prepare %s", ctx.Cmd(), imagePath) uuid := runRktAndGetUUID(t, cmd) shortUUID := strings.Split(uuid, "-")[0] cmd = fmt.Sprintf("%s run-prepared %s", ctx.Cmd(), shortUUID) runRktAndCheckOutput(t, cmd, "", false) cgs, err := getPodCgroups(shortUUID) if err != nil { t.Fatalf("error getting pod cgroups: %v", err) } if len(cgs) == 0 { t.Fatalf("expected pod cgroup directories after run, but found none") } rmCmd := fmt.Sprintf("%s rm %s", ctx.Cmd(), shortUUID) spawnAndWaitOrFail(t, rmCmd, 0) cgs, err = getPodCgroups(shortUUID) if err != nil { t.Fatalf("error getting pod cgroups: %v", err) } if len(cgs) > 0 { t.Fatalf(fmt.Sprintf("expected no pod cgroup directories after GC, but found %d: %v", len(cgs), cgs)) } }
func TestAppIsolatorMemory(t *testing.T) { ok, err := cgroup.IsIsolatorSupported("memory") if err != nil { t.Fatalf("Error checking memory isolator support: %v", err) } if !ok { t.Skip("Memory isolator not supported.") } ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() t.Logf("Running test: %v", memoryTest.testName) aciFileName := patchTestACI("rkt-inspect-isolators.aci", memoryTest.aciBuildArgs...) defer os.Remove(aciFileName) rktCmd := fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s", ctx.Cmd(), aciFileName) expectedLine := "Memory Limit: " + strconv.Itoa(maxMemoryUsage) runRktAndCheckOutput(t, rktCmd, expectedLine, false) rktCmd = fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s --memory 42Mi", ctx.Cmd(), aciFileName) expectedLine = "Memory Limit: " + strconv.Itoa(42*1024*1024) runRktAndCheckOutput(t, rktCmd, expectedLine, false) }
func testFetchDefault(t *testing.T, arg string, image string, imageArgs string, finalURL string) { remoteFetchMsgTpl := `remote fetching from URL %q` storeMsgTpl := `using image from local store for .* %s` if finalURL == "" { finalURL = image } remoteFetchMsg := fmt.Sprintf(remoteFetchMsgTpl, finalURL) storeMsg := fmt.Sprintf(storeMsgTpl, image) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() cmd := fmt.Sprintf("%s %s %s %s", ctx.Cmd(), arg, image, imageArgs) // 1. Run cmd with the image not available in the store, should get $remoteFetchMsg. child := spawnOrFail(t, cmd) err := expectWithOutput(child, remoteFetchMsg) if exitErr := checkExitStatus(child); exitErr != nil { t.Logf("%v", exitErr) t.Skip("remote fetching failed, probably a network failure. Skipping...") } if err != nil { t.Fatalf("%q should be found: %v", remoteFetchMsg, err) } // 2. Run cmd with the image available in the store, should get $storeMsg. runRktAndCheckRegexOutput(t, cmd, storeMsg) }
func TestAppIsolatorCPU(t *testing.T) { isUnified, err := cgroup.IsCgroupUnified("/") if err != nil { t.Fatalf("Error determining the cgroup version: %v", err) } if isUnified { // TODO: for now kernel does not support cpu isolator in cgroup2. // Write a test when it does. t.Skip("kernel does not support cpu isolator in cgroup2.") } ok, err := cgroup.IsIsolatorSupported("cpu") if err != nil { t.Fatalf("Error checking cpu isolator support: %v", err) } if !ok { t.Skip("CPU isolator not supported.") } ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() t.Logf("Running test: %v", cpuTest.testName) aciFileName := patchTestACI("rkt-inspect-isolators.aci", cpuTest.aciBuildArgs...) defer os.Remove(aciFileName) rktCmd := fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s", ctx.Cmd(), aciFileName) expectedLine := "CPU Quota: " + strconv.Itoa(CPUQuota) runRktAndCheckOutput(t, rktCmd, expectedLine, false) rktCmd = fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s --cpu 900m", ctx.Cmd(), aciFileName) expectedLine = "CPU Quota: " + strconv.Itoa(900) runRktAndCheckOutput(t, rktCmd, expectedLine, false) }
func TestAuthSanity(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() server, image := runAuthServer(t, taas.AuthNone) defer authCleanup(server, image) expectedRunRkt(ctx, t, server.URL, "sanity", authSuccessfulDownload) }
func TestGC(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() imagePath := getInspectImagePath() // Finished pods. importImageAndRun(imagePath, t, ctx) // Prepared pods. importImageAndPrepare(imagePath, t, ctx) // Abort prepare. cmd := fmt.Sprintf("%s --insecure-options=image prepare %s %s", ctx.Cmd(), imagePath, imagePath) spawnAndWaitOrFail(t, cmd, 254) gcCmd := fmt.Sprintf("%s gc --mark-only=true --expire-prepared=0 --grace-period=0", ctx.Cmd()) spawnAndWaitOrFail(t, gcCmd, 0) pods := podsRemaining(t, ctx) if len(pods) == 0 { t.Fatalf("pods should still be present in rkt's data directory") } gcCmd = fmt.Sprintf("%s gc --mark-only=false --expire-prepared=0 --grace-period=0", ctx.Cmd()) spawnAndWaitOrFail(t, gcCmd, 0) pods = podsRemaining(t, ctx) if len(pods) != 0 { t.Fatalf("no pods should exist rkt's data directory, but found: %v", pods) } }
func TestCapsNonRoot(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() for i, tt := range capsTests { args := []string{"--exec=/inspect --print-caps-pid=0 --print-user", "--user=9000", "--group=9000"} if tt.capIsolator != "" { args = append(args, "--capability="+tt.capIsolator) } fileName := patchTestACI("rkt-inspect-print-caps-nonroot.aci", args...) defer os.Remove(fileName) t.Logf("Running test #%v: %v [non-root]", i, tt.testName) cmd := fmt.Sprintf("%s --debug --insecure-options=image run --mds-register=false --set-env=CAPABILITY=%d %s", ctx.Cmd(), int(tt.capa), fileName) child := spawnOrFail(t, cmd) expectedLine := tt.capa.String() if tt.nonrootCapExpected { expectedLine += "=enabled" } else { expectedLine += "=disabled" } if err := expectWithOutput(child, expectedLine); err != nil { t.Fatalf("Expected %q but not found: %v", expectedLine, err) } if err := expectWithOutput(child, "User: uid=9000 euid=9000 gid=9000 egid=9000"); err != nil { t.Fatalf("Expected user 9000 but not found: %v", err) } waitOrFail(t, child, 0) ctx.Reset() } }
func TestJournalLink(t *testing.T) { if !sd_util.IsRunningSystemd() { t.Skip("Systemd is not running on the host.") } if _, err := os.Stat(journalDir); os.IsNotExist(err) { t.Skip("Persistent journaling disabled.") } image := getInspectImagePath() ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() rktCmd := fmt.Sprintf("%s prepare --insecure-options=image %s", ctx.Cmd(), image) uuid := runRktAndGetUUID(t, rktCmd) rktCmd = fmt.Sprintf("%s run-prepared %s", ctx.Cmd(), uuid) spawnAndWaitOrFail(t, rktCmd, 0) machineID := strings.Replace(uuid, "-", "", -1) journalPath := filepath.Join("/var/log/journal", machineID) link, err := os.Readlink(journalPath) if err != nil { t.Fatalf("failed to read journal link %q", journalPath) } podJournal := filepath.Join(ctx.DataDir(), "pods/run", uuid, "stage1/rootfs/var/log/journal/", machineID) if link != podJournal { t.Fatalf("unexpected target of journal link: %q. Expected %q", link, podJournal) } }
func TestFlyNetns(t *testing.T) { testImageArgs := []string{"--exec=/inspect --print-netns"} testImage := patchTestACI("rkt-inspect-stage1-fly.aci", testImageArgs...) defer os.Remove(testImage) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() cmd := fmt.Sprintf("%s --debug --insecure-options=image run %s", ctx.Cmd(), testImage) child := spawnOrFail(t, cmd) ctx.RegisterChild(child) defer waitOrFail(t, child, 0) expectedRegex := `NetNS: (net:\[\d+\])` result, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { t.Fatalf("Error: %v\nOutput: %v", err, out) } ns, err := os.Readlink("/proc/self/ns/net") if err != nil { t.Fatalf("Cannot evaluate NetNS symlink: %v", err) } if nsChanged := ns != result[1]; nsChanged { t.Fatalf("container left host netns") } }
func TestCapsSeveralAppWithPatches(t *testing.T) { // All the following images are launched together in the same pod ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() for i, tt := range appCapsTests { patches := []string{ fmt.Sprintf("--name=%s", tt.testName), fmt.Sprintf("--exec=/inspect --print-caps-pid=0 --suffix-msg=%s", tt.testName), } if tt.capRetainSet != "x" { patches = append(patches, "--capability="+tt.capRetainSet) } if tt.capRemoveSet != "x" { patches = append(patches, "--revoke-capability="+tt.capRemoveSet) } imageFile := patchTestACI(tt.testName+".aci", patches...) defer os.Remove(imageFile) appCapsTests[i].imageFile = imageFile t.Logf("Built image %q", imageFile) } // Generate the rkt arguments to launch all the apps in the same pod rktArgs := "" for _, tt := range appCapsTests { rktArgs += " " + tt.imageFile } cmd := fmt.Sprintf("%s --insecure-options=image run %s", ctx.Cmd(), rktArgs) capsSeveralAppsRunAndCheckOutput(t, ctx, cmd) }
func TestImageRunRmDuplicate(t *testing.T) { imageFile := patchTestACI(unreferencedACI, fmt.Sprintf("--name=%s", unreferencedApp)) defer os.Remove(imageFile) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() cmd := fmt.Sprintf("%s --insecure-options=image fetch %s", ctx.Cmd(), imageFile) t.Logf("Fetching %s", imageFile) spawnAndWaitOrFail(t, cmd, true) // at this point we know that RKT_INSPECT_IMAGE env var is not empty referencedACI := os.Getenv("RKT_INSPECT_IMAGE") cmd = fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s", ctx.Cmd(), referencedACI) t.Logf("Running %s", referencedACI) spawnAndWaitOrFail(t, cmd, true) t.Logf("Retrieving %s image ID", referencedApp) referencedImageID, err := getImageID(ctx, referencedApp) if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } t.Logf("Retrieving %s image ID", unreferencedApp) unreferencedImageID, err := getImageID(ctx, unreferencedApp) if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } t.Logf("Removing image for app %s (should work)", referencedApp) removeImage(t, ctx, referencedApp, referencedImageID) t.Logf("Removing image for app %s (should work)", unreferencedApp) removeImage(t, ctx, unreferencedImageID, unreferencedApp) }
func TestImageRunRmName(t *testing.T) { imageFile := patchTestACI(unreferencedACI, fmt.Sprintf("--name=%s", unreferencedApp)) defer os.Remove(imageFile) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() cmd := fmt.Sprintf("%s --insecure-options=image fetch %s", ctx.Cmd(), imageFile) spawnAndWaitOrFail(t, cmd, true) // at this point we know that RKT_INSPECT_IMAGE env var is not empty referencedACI := os.Getenv("RKT_INSPECT_IMAGE") cmd = fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s", ctx.Cmd(), referencedACI) spawnAndWaitOrFail(t, cmd, true) t.Logf("Retrieving stage1 image name") stage1ImageName := getImageName(t, ctx, stage1App) t.Logf("Removing stage1 image (should work)") removeImage(t, ctx, stage1ImageName) t.Logf("Removing image for app %s (should work)", referencedApp) removeImage(t, ctx, referencedApp) t.Logf("Removing image for app %s (should work)", unreferencedApp) removeImage(t, ctx, unreferencedApp) }
func TestInteractive(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() for i, tt := range interactiveTests { t.Logf("Running test #%v: %v", i, tt.testName) aciFileName := patchTestACI("rkt-inspect-interactive.aci", tt.aciBuildArgs...) defer os.Remove(aciFileName) rktCmd := fmt.Sprintf("%s %s", ctx.Cmd(), tt.rktArgs) rktCmd = strings.Replace(rktCmd, "^INTERACTIVE^", aciFileName, -1) child := spawnOrFail(t, rktCmd) if tt.say != "" { if err := expectTimeoutWithOutput(child, "Enter text:", time.Minute); err != nil { t.Fatalf("Waited for the prompt but not found #%v: %v", i, err) } if err := child.SendLine(tt.say); err != nil { t.Fatalf("Failed to send %q on the prompt #%v: %v", tt.say, i, err) } } if err := expectTimeoutWithOutput(child, tt.expect, time.Minute); err != nil { t.Fatalf("Expected %q but not found #%v: %v", tt.expect, i, err) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } }
/* * Default net * --- * Container must be in a separate network namespace */ func NewTestNetDefaultNetNS() testutils.Test { return testutils.TestFunc(func(t *testing.T) { testImageArgs := []string{"--exec=/inspect --print-netns"} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() f := func(argument string) { cmd := fmt.Sprintf("%s --debug --insecure-options=image run %s --mds-register=false %s", ctx.Cmd(), argument, testImage) child := spawnOrFail(t, cmd) defer waitOrFail(t, child, 0) expectedRegex := `NetNS: (net:\[\d+\])` result, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { t.Fatalf("Error: %v\nOutput: %v", err, out) } ns, err := os.Readlink("/proc/self/ns/net") if err != nil { t.Fatalf("Cannot evaluate NetNS symlink: %v", err) } if nsChanged := ns != result[1]; !nsChanged { t.Fatalf("container did not leave host netns") } } f("--net=default") f("") }) }
/* * NewNetDefaultGWTest checks if default gateway is correct if only configured network is one provided by flannel. */ func NewNetDefaultGWTest() testutils.Test { return testutils.TestFunc(func(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() _, ntFlannel, err := mockFlannelNetwork(t, ctx) if err != nil { t.Errorf("Can't mock flannel network: %v", err) } defer os.Remove(ntFlannel.SubnetFile) testImageArgs := []string{"--exec=/inspect --print-defaultgwv4"} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=%s --mds-register=false %s", ctx.Cmd(), ntFlannel.Name, testImage) child := spawnOrFail(t, cmd) defer waitOrFail(t, child, 0) expectedRegex := `DefaultGWv4: (\d+\.\d+\.\d+\.\d+)` if _, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, time.Minute); err != nil { t.Fatalf("No default gateway!\nError: %v\nOutput: %v", err, out) } }) }
/* * Pass the IP arg to the default networks, ensure it works */ func NewNetDefaultIPArgTest() testutils.Test { doTest := func(netArg, expectedIP string, t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() appCmd := "--exec=/inspect -- --print-ipv4=eth0" cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=\"%s\" --mds-register=false %s %s", ctx.Cmd(), netArg, getInspectImagePath(), appCmd) child := spawnOrFail(t, cmd) defer waitOrFail(t, child, 0) expectedRegex := `IPv4: (\d+\.\d+\.\d+\.\d+)` result, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second) if err != nil { t.Fatalf("Error: %v\nOutput: %v", err, out) return } containerIP := result[1] if expectedIP != containerIP { t.Fatalf("--net=%s setting IP failed: Got %q but expected %q", netArg, containerIP, expectedIP) } } return testutils.TestFunc(func(t *testing.T) { doTest("default:IP=172.16.28.123", "172.16.28.123", t) doTest("default-restricted:IP=172.17.42.42", "172.17.42.42", t) }) }
func TestAPIServiceListInspectImages(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() svc := startAPIService(t, ctx) defer stopAPIService(t, svc) c, conn := newAPIClientOrFail(t, "localhost:15441") defer conn.Close() resp, err := c.ListImages(context.Background(), &v1alpha.ListImagesRequest{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } if len(resp.Images) != 0 { t.Errorf("Unexpected result: %v, should see zero images", resp.Images) } _, err = patchImportAndFetchHash("rkt-inspect-sleep.aci", []string{"--exec=/inspect"}, t, ctx) if err != nil { t.Fatalf("%v", err) } // ListImages(detail=false). resp, err = c.ListImages(context.Background(), &v1alpha.ListImagesRequest{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } if len(resp.Images) == 0 { t.Errorf("Unexpected result: %v, should see non-zero images", resp.Images) } for _, m := range resp.Images { checkImageBasics(t, ctx, m) // Test InspectImage(). inspectResp, err := c.InspectImage(context.Background(), &v1alpha.InspectImageRequest{Id: m.Id}) if err != nil { t.Fatalf("Unexpected error: %v", err) } checkImageDetails(t, ctx, inspectResp.Image) } // ListImages(detail=true). resp, err = c.ListImages(context.Background(), &v1alpha.ListImagesRequest{Detail: true}) if err != nil { t.Fatalf("Unexpected error: %v", err) } if len(resp.Images) == 0 { t.Errorf("Unexpected result: %v, should see non-zero images", resp.Images) } for _, m := range resp.Images { checkImageDetails(t, ctx, m) } }