From aeaa7564d6a65ebf8cd418f26a0adff1a69ac02c Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 29 Aug 2024 21:15:54 +0000 Subject: [PATCH] feat(tools/cosmovisor): pass stdin to process (#21462) --- tools/cosmovisor/CHANGELOG.md | 12 ++++--- tools/cosmovisor/cmd/cosmovisor/run.go | 4 +-- tools/cosmovisor/cmd/cosmovisor/run_config.go | 9 +++++ tools/cosmovisor/process.go | 3 +- tools/cosmovisor/process_test.go | 36 +++++++++++-------- 5 files changed, 43 insertions(+), 21 deletions(-) diff --git a/tools/cosmovisor/CHANGELOG.md b/tools/cosmovisor/CHANGELOG.md index 600b58fd352e..a4c78e469c45 100644 --- a/tools/cosmovisor/CHANGELOG.md +++ b/tools/cosmovisor/CHANGELOG.md @@ -36,16 +36,20 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Improvements + +* [#21462](https://github.com/cosmos/cosmos-sdk/pull/21462) Pass `stdin` to binary. + ## v1.6.0 - 2024-08-12 ## Improvements * Bump `cosmossdk.io/x/upgrade` to v0.1.4 (including go-getter vulnerability fix) * [#19995](https://github.com/cosmos/cosmos-sdk/pull/19995): - * `init command` writes the configuration to the config file only at the default path `DAEMON_HOME/cosmovisor/config.toml`. - * Provide `--cosmovisor-config` flag with value as args to provide the path to the configuration file in the `run` command. `run --cosmovisor-config (other cmds with flags) ...`. - * Add `--cosmovisor-config` flag to provide `config.toml` path to the configuration file in root command used by `add-upgrade` and `config` subcommands. - * `config command` now displays the configuration from the config file if it is provided. If the config file is not provided, it will display the configuration from the environment variables. + * `init command` writes the configuration to the config file only at the default path `DAEMON_HOME/cosmovisor/config.toml`. + * Provide `--cosmovisor-config` flag with value as args to provide the path to the configuration file in the `run` command. `run --cosmovisor-config (other cmds with flags) ...`. + * Add `--cosmovisor-config` flag to provide `config.toml` path to the configuration file in root command used by `add-upgrade` and `config` subcommands. + * `config command` now displays the configuration from the config file if it is provided. If the config file is not provided, it will display the configuration from the environment variables. ## Bug Fixes diff --git a/tools/cosmovisor/cmd/cosmovisor/run.go b/tools/cosmovisor/cmd/cosmovisor/run.go index 0e1513cf6766..f835b59e5280 100644 --- a/tools/cosmovisor/cmd/cosmovisor/run.go +++ b/tools/cosmovisor/cmd/cosmovisor/run.go @@ -45,11 +45,11 @@ func run(cfgPath string, args []string, options ...RunOption) error { return err } - doUpgrade, err := launcher.Run(args, runCfg.StdOut, runCfg.StdErr) + doUpgrade, err := launcher.Run(args, runCfg.StdIn, runCfg.StdOut, runCfg.StdErr) // if RestartAfterUpgrade, we launch after a successful upgrade (given that condition launcher.Run returns nil) for cfg.RestartAfterUpgrade && err == nil && doUpgrade { logger.Info("upgrade detected, relaunching", "app", cfg.Name) - doUpgrade, err = launcher.Run(args, runCfg.StdOut, runCfg.StdErr) + doUpgrade, err = launcher.Run(args, runCfg.StdIn, runCfg.StdOut, runCfg.StdErr) } if doUpgrade && err == nil { diff --git a/tools/cosmovisor/cmd/cosmovisor/run_config.go b/tools/cosmovisor/cmd/cosmovisor/run_config.go index 3f865c610933..f025b06eb619 100644 --- a/tools/cosmovisor/cmd/cosmovisor/run_config.go +++ b/tools/cosmovisor/cmd/cosmovisor/run_config.go @@ -7,18 +7,27 @@ import ( // DefaultRunConfig defintes a default RunConfig that writes to os.Stdout and os.Stderr var DefaultRunConfig = RunConfig{ + StdIn: os.Stdin, StdOut: os.Stdout, StdErr: os.Stderr, } // RunConfig defines the configuration for running a command type RunConfig struct { + StdIn io.Reader StdOut io.Writer StdErr io.Writer } type RunOption func(*RunConfig) +// StdInRunOption sets the StdIn reader for the Run command +func StdInRunOption(r io.Reader) RunOption { + return func(cfg *RunConfig) { + cfg.StdIn = r + } +} + // StdOutRunOption sets the StdOut writer for the Run command func StdOutRunOption(w io.Writer) RunOption { return func(cfg *RunConfig) { diff --git a/tools/cosmovisor/process.go b/tools/cosmovisor/process.go index c288515005fd..ac759bde39f4 100644 --- a/tools/cosmovisor/process.go +++ b/tools/cosmovisor/process.go @@ -39,7 +39,7 @@ func NewLauncher(logger log.Logger, cfg *Config) (Launcher, error) { // Run launches the app in a subprocess and returns when the subprocess (app) // exits (either when it dies, or *after* a successful upgrade.) and upgrade finished. // Returns true if the upgrade request was detected and the upgrade process started. -func (l Launcher) Run(args []string, stdout, stderr io.Writer) (bool, error) { +func (l Launcher) Run(args []string, stdin io.Reader, stdout, stderr io.Writer) (bool, error) { bin, err := l.cfg.CurrentBin() if err != nil { return false, fmt.Errorf("error creating symlink to genesis: %w", err) @@ -51,6 +51,7 @@ func (l Launcher) Run(args []string, stdout, stderr io.Writer) (bool, error) { l.logger.Info("running app", "path", bin, "args", args) cmd := exec.Command(bin, args...) + cmd.Stdin = stdin cmd.Stdout = stdout cmd.Stderr = stderr if err := cmd.Start(); err != nil { diff --git a/tools/cosmovisor/process_test.go b/tools/cosmovisor/process_test.go index 09658f265cdb..e019c8b98fee 100644 --- a/tools/cosmovisor/process_test.go +++ b/tools/cosmovisor/process_test.go @@ -7,6 +7,7 @@ import ( "bytes" "fmt" "io/fs" + "os" "path/filepath" "sync" "testing" @@ -28,6 +29,7 @@ func TestLaunchProcess(t *testing.T) { logger := log.NewTestLogger(t).With(log.ModuleKey, "cosmosvisor") // should run the genesis binary and produce expected output + stdin, _ := os.Open(os.DevNull) stdout, stderr := newBuffer(), newBuffer() currentBin, err := cfg.CurrentBin() require.NoError(t, err) @@ -39,7 +41,7 @@ func TestLaunchProcess(t *testing.T) { upgradeFile := cfg.UpgradeInfoFilePath() args := []string{"foo", "bar", "1234", upgradeFile} - doUpgrade, err := launcher.Run(args, stdout, stderr) + doUpgrade, err := launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.True(t, doUpgrade) require.Empty(t, stderr.String()) @@ -54,7 +56,7 @@ func TestLaunchProcess(t *testing.T) { stdout.Reset() stderr.Reset() - doUpgrade, err = launcher.Run(args, stdout, stderr) + doUpgrade, err = launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.False(t, doUpgrade) require.Empty(t, stderr.String()) @@ -72,6 +74,7 @@ func TestPlanDisableRecase(t *testing.T) { logger := log.NewTestLogger(t).With(log.ModuleKey, "cosmosvisor") // should run the genesis binary and produce expected output + stdin, _ := os.Open(os.DevNull) stdout, stderr := newBuffer(), newBuffer() currentBin, err := cfg.CurrentBin() require.NoError(t, err) @@ -83,7 +86,7 @@ func TestPlanDisableRecase(t *testing.T) { upgradeFile := cfg.UpgradeInfoFilePath() args := []string{"foo", "bar", "1234", upgradeFile} - doUpgrade, err := launcher.Run(args, stdout, stderr) + doUpgrade, err := launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.True(t, doUpgrade) require.Empty(t, stderr.String()) @@ -98,7 +101,7 @@ func TestPlanDisableRecase(t *testing.T) { stdout.Reset() stderr.Reset() - doUpgrade, err = launcher.Run(args, stdout, stderr) + doUpgrade, err = launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.False(t, doUpgrade) require.Empty(t, stderr.String()) @@ -115,6 +118,7 @@ func TestLaunchProcessWithRestartDelay(t *testing.T) { logger := log.NewTestLogger(t).With(log.ModuleKey, "cosmosvisor") // should run the genesis binary and produce expected output + stdin, _ := os.Open(os.DevNull) stdout, stderr := newBuffer(), newBuffer() currentBin, err := cfg.CurrentBin() require.NoError(t, err) @@ -126,7 +130,7 @@ func TestLaunchProcessWithRestartDelay(t *testing.T) { upgradeFile := cfg.UpgradeInfoFilePath() start := time.Now() - doUpgrade, err := launcher.Run([]string{"foo", "bar", "1234", upgradeFile}, stdout, stderr) + doUpgrade, err := launcher.Run([]string{"foo", "bar", "1234", upgradeFile}, stdin, stdout, stderr) require.NoError(t, err) require.True(t, doUpgrade) @@ -145,6 +149,7 @@ func TestPlanShutdownGrace(t *testing.T) { logger := log.NewTestLogger(t).With(log.ModuleKey, "cosmosvisor") // should run the genesis binary and produce expected output + stdin, _ := os.Open(os.DevNull) stdout, stderr := newBuffer(), newBuffer() currentBin, err := cfg.CurrentBin() require.NoError(t, err) @@ -156,7 +161,7 @@ func TestPlanShutdownGrace(t *testing.T) { upgradeFile := cfg.UpgradeInfoFilePath() args := []string{"foo", "bar", "1234", upgradeFile} - doUpgrade, err := launcher.Run(args, stdout, stderr) + doUpgrade, err := launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.True(t, doUpgrade) require.Empty(t, stderr.String()) @@ -171,7 +176,7 @@ func TestPlanShutdownGrace(t *testing.T) { stdout.Reset() stderr.Reset() - doUpgrade, err = launcher.Run(args, stdout, stderr) + doUpgrade, err = launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.False(t, doUpgrade) require.Empty(t, stderr.String()) @@ -201,9 +206,10 @@ func TestLaunchProcessWithDownloads(t *testing.T) { launcher, err := cosmovisor.NewLauncher(logger, cfg) require.NoError(t, err) + stdin, _ := os.Open(os.DevNull) stdout, stderr := newBuffer(), newBuffer() args := []string{"some", "args", upgradeFilename} - doUpgrade, err := launcher.Run(args, stdout, stderr) + doUpgrade, err := launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.True(t, doUpgrade) require.Empty(t, stderr.String()) @@ -216,7 +222,7 @@ func TestLaunchProcessWithDownloads(t *testing.T) { stdout.Reset() stderr.Reset() args = []string{"run", "--fast", upgradeFilename} - doUpgrade, err = launcher.Run(args, stdout, stderr) + doUpgrade, err = launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.Empty(t, stderr.String()) @@ -231,7 +237,7 @@ func TestLaunchProcessWithDownloads(t *testing.T) { args = []string{"end", "--halt", upgradeFilename} stdout.Reset() stderr.Reset() - doUpgrade, err = launcher.Run(args, stdout, stderr) + doUpgrade, err = launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.False(t, doUpgrade) require.Empty(t, stderr.String()) @@ -270,9 +276,10 @@ func TestLaunchProcessWithDownloadsAndMissingPreupgrade(t *testing.T) { require.NoError(t, err) // Missing Preupgrade Script + stdin, _ := os.Open(os.DevNull) stdout, stderr := newBuffer(), newBuffer() args := []string{"some", "args", upgradeFilename} - _, err = launcher.Run(args, stdout, stderr) + _, err = launcher.Run(args, stdin, stdout, stderr) require.ErrorContains(t, err, "missing.sh") require.ErrorIs(t, err, fs.ErrNotExist) @@ -305,9 +312,10 @@ func TestLaunchProcessWithDownloadsAndPreupgrade(t *testing.T) { launcher, err := cosmovisor.NewLauncher(logger, cfg) require.NoError(t, err) + stdin, _ := os.Open(os.DevNull) stdout, stderr := newBuffer(), newBuffer() args := []string{"some", "args", upgradeFilename} - doUpgrade, err := launcher.Run(args, stdout, stderr) + doUpgrade, err := launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.True(t, doUpgrade) @@ -324,7 +332,7 @@ func TestLaunchProcessWithDownloadsAndPreupgrade(t *testing.T) { stdout.Reset() stderr.Reset() args = []string{"run", "--fast", upgradeFilename} - doUpgrade, err = launcher.Run(args, stdout, stderr) + doUpgrade, err = launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.Empty(t, stderr.String()) @@ -342,7 +350,7 @@ func TestLaunchProcessWithDownloadsAndPreupgrade(t *testing.T) { args = []string{"end", "--halt", upgradeFilename} stdout.Reset() stderr.Reset() - doUpgrade, err = launcher.Run(args, stdout, stderr) + doUpgrade, err = launcher.Run(args, stdin, stdout, stderr) require.NoError(t, err) require.False(t, doUpgrade) require.Empty(t, stderr.String())