Skip to content

Commit

Permalink
feat(tools/cosmovisor): pass stdin to process (#21462)
Browse files Browse the repository at this point in the history
  • Loading branch information
julienrbrt authored Aug 29, 2024
1 parent 41a9af7 commit aeaa756
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 21 deletions.
12 changes: 8 additions & 4 deletions tools/cosmovisor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <path> (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 <path> (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

Expand Down
4 changes: 2 additions & 2 deletions tools/cosmovisor/cmd/cosmovisor/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions tools/cosmovisor/cmd/cosmovisor/run_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion tools/cosmovisor/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 {
Expand Down
36 changes: 22 additions & 14 deletions tools/cosmovisor/process_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"fmt"
"io/fs"
"os"
"path/filepath"
"sync"
"testing"
Expand All @@ -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)
Expand All @@ -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())
Expand All @@ -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())
Expand All @@ -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)
Expand All @@ -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())
Expand All @@ -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())
Expand All @@ -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)
Expand All @@ -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)

Expand All @@ -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)
Expand All @@ -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())
Expand All @@ -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())
Expand Down Expand Up @@ -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())
Expand All @@ -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())
Expand All @@ -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())
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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())
Expand All @@ -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())
Expand Down

0 comments on commit aeaa756

Please sign in to comment.