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 waitOrFail(t *testing.T, child *gexpect.ExpectSubprocess, expectedStatus int) { err := child.Wait() status, _ := common.GetExitStatus(err) if status != expectedStatus { t.Fatalf("rkt terminated with unexpected status %d, expected %d\nOutput:\n%s", status, expectedStatus, child.Collect()) } }
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) }
func runRkt(t *testing.T, rktCmd string, uid, gid int) (string, int) { child, err := gexpect.Command(rktCmd) if err != nil { t.Fatalf("cannot exec rkt: %v", err) } if gid != 0 { child.Cmd.SysProcAttr = &syscall.SysProcAttr{} child.Cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)} } err = child.Start() if err != nil { t.Fatalf("cannot start rkt: %v", err) } _, linesChan := child.AsyncInteractChannels() var buf bytes.Buffer for line := range linesChan { buf.WriteString(line + "\n") // reappend newline } status, _ := common.GetExitStatus(child.Wait()) return buf.String(), status }
func checkExitStatus(child *gexpect.ExpectSubprocess) error { err := child.Wait() status, _ := common.GetExitStatus(err) if status != 0 { return fmt.Errorf("rkt terminated with unexpected status %d, expected %d\nOutput:\n%s", status, 0, child.Collect()) } return nil }
func StopApp(cfg StopConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } defer pod.Close() _, pm, err := pod.PodManifest() if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } var mutable bool ms, ok := pm.Annotations.Get("coreos.com/rkt/stage1/mutable") if ok { mutable, err = strconv.ParseBool(ms) if err != nil { return errwrap.Wrap(errors.New("error parsing mutable annotation"), err) } } if !mutable { return errors.New("immutable pod: cannot start application") } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } args := []string{ fmt.Sprintf("--app=%s", cfg.AppName), } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStopEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { status, err := common.GetExitStatus(err) // exit status 5 comes from systemctl and means the unit doesn't exist if status == 5 { return fmt.Errorf("app %q is not running", app.Name) } return err } return nil }
// waitOrFail waits for the child to exit, draining all its output. // If a non-negative return value is provided, child exit status must match. func waitOrFail(t *testing.T, child *gexpect.ExpectSubprocess, expectedStatus int) { bufOut := []string{} // TODO(lucab): gexpect should accept those channels from the caller ttyIn, ttyOut := child.AsyncInteractChannels() close(ttyIn) // drain output till gexpect closes the channel (on EOF or error) for line := range ttyOut { bufOut = append(bufOut, line) } err := child.Wait() status, _ := common.GetExitStatus(err) if expectedStatus >= 0 && status != expectedStatus { t.Fatalf("rkt terminated with unexpected status %d, expected %d\nOutput:\n%s", status, expectedStatus, bufOut) } }
func StopApp(cfg StopConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } defer pod.Close() pm, err := pod.SandboxManifest() if err != nil { return errwrap.Wrap(errors.New("cannot stop application"), err) } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } args := []string{ fmt.Sprintf("--debug=%t", cfg.Debug), fmt.Sprintf("--app=%s", cfg.AppName), } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStopEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { status, err := common.GetExitStatus(err) // exit status 5 comes from systemctl and means the unit doesn't exist if status == 5 { return fmt.Errorf("app %q is not running", app.Name) } return err } return nil }
func RmApp(cfg RmConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod"), err) } defer pod.Close() debug("locking sandbox manifest") if err := pod.ExclusiveLockManifest(); err != nil { return errwrap.Wrap(errors.New("failed to lock sandbox manifest"), err) } defer pod.UnlockManifest() pm, err := pod.SandboxManifest() if err != nil { return errwrap.Wrap(errors.New("cannot remove application, sandbox validation failed"), err) } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } if cfg.PodPID > 0 { // Call app-stop and app-rm entrypoint only if the pod is still running. // Otherwise, there's not much we can do about it except unmounting/removing // the file system. args := []string{ fmt.Sprintf("--debug=%t", cfg.Debug), fmt.Sprintf("--app=%s", cfg.AppName), } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStopEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { status, err := common.GetExitStatus(err) // ignore nonexistent units failing to stop. Exit status 5 // comes from systemctl and means the unit doesn't exist if err != nil { return err } else if status != 5 { return fmt.Errorf("exit status %d", status) } } ce.EntrypointName = appRmEntrypoint if err := ce.Run(); err != nil { return err } } if cfg.UsesOverlay { treeStoreID, err := ioutil.ReadFile(common.AppTreeStoreIDPath(cfg.PodPath, *cfg.AppName)) if err != nil { return err } appRootfs := common.AppRootfsPath(cfg.PodPath, *cfg.AppName) if err := syscall.Unmount(appRootfs, 0); err != nil { return err } ts := filepath.Join(cfg.PodPath, "overlay", string(treeStoreID)) if err := os.RemoveAll(ts); err != nil { return errwrap.Wrap(errors.New("error removing app info directory"), err) } } appInfoDir := common.AppInfoPath(cfg.PodPath, *cfg.AppName) if err := os.RemoveAll(appInfoDir); err != nil { return errwrap.Wrap(errors.New("error removing app info directory"), err) } if err := os.RemoveAll(common.AppPath(cfg.PodPath, *cfg.AppName)); err != nil { return err } appStatusPath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "status", cfg.AppName.String()) if err := os.Remove(appStatusPath); err != nil && !os.IsNotExist(err) { return err } envPath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "env", cfg.AppName.String()) if err := os.Remove(envPath); err != nil && !os.IsNotExist(err) { return err } for i, app := range pm.Apps { if app.Name == *cfg.AppName { pm.Apps = append(pm.Apps[:i], pm.Apps[i+1:]...) break } } return pod.UpdateManifest(pm, cfg.PodPath) }
func RmApp(cfg RmConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod"), err) } defer pod.Close() debug("locking pod manifest") if err := pod.ExclusiveManifestLock(); err != nil { return errwrap.Wrap(errors.New("failed to lock pod manifest"), err) } defer pod.ManifestUnlock() _, pm, err := pod.PodManifest() if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } var mutable bool ms, ok := pm.Annotations.Get("coreos.com/rkt/stage1/mutable") if ok { mutable, err = strconv.ParseBool(ms) if err != nil { return errwrap.Wrap(errors.New("error parsing mutable annotation"), err) } } if !mutable { return errors.New("immutable pod: cannot remove application") } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } if cfg.PodPID > 0 { // Call app-stop and app-rm entrypoint only if the pod is still running. // Otherwise, there's not much we can do about it except unmounting/removing // the file system. args := []string{ fmt.Sprintf("--app=%s", cfg.AppName), } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStopEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { status, err := common.GetExitStatus(err) // ignore nonexistent units failing to stop. Exit status 5 // comes from systemctl and means the unit doesn't exist if err != nil { return err } else if status != 5 { return fmt.Errorf("exit status %d", status) } } ce.EntrypointName = appRmEntrypoint if err := ce.Run(); err != nil { return err } } if cfg.UsesOverlay { treeStoreID, err := ioutil.ReadFile(common.AppTreeStoreIDPath(cfg.PodPath, *cfg.AppName)) if err != nil { return err } appRootfs := common.AppRootfsPath(cfg.PodPath, *cfg.AppName) if err := syscall.Unmount(appRootfs, 0); err != nil { return err } ts := filepath.Join(cfg.PodPath, "overlay", string(treeStoreID)) if err := os.RemoveAll(ts); err != nil { return errwrap.Wrap(errors.New("error removing app info directory"), err) } } appInfoDir := common.AppInfoPath(cfg.PodPath, *cfg.AppName) if err := os.RemoveAll(appInfoDir); err != nil { return errwrap.Wrap(errors.New("error removing app info directory"), err) } if err := os.RemoveAll(common.AppPath(cfg.PodPath, *cfg.AppName)); err != nil { return err } appStatusPath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "status", cfg.AppName.String()) if err := os.Remove(appStatusPath); err != nil && !os.IsNotExist(err) { return err } envPath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "env", cfg.AppName.String()) if err := os.Remove(envPath); err != nil && !os.IsNotExist(err) { return err } removeAppFromPodManifest(pm, cfg.AppName) if err := updatePodManifest(cfg.PodPath, pm); err != nil { return err } return nil }