Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tools/cosmovisor): pass stdin to process #21462

Merged
merged 2 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading