From 019444ae4328beaca32f2f8416ee5edbac2ef30b Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 26 Apr 2022 23:25:02 +0200 Subject: [PATCH] fix(cosmovisor): let `cosmovisor version` return a valid json (#11731) --- cosmovisor/CHANGELOG.md | 2 + cosmovisor/args.go | 20 +++-- cosmovisor/args_test.go | 5 +- cosmovisor/cmd/cosmovisor/cmd/help.go | 4 +- cosmovisor/cmd/cosmovisor/cmd/root.go | 20 +++-- cosmovisor/cmd/cosmovisor/cmd/run.go | 21 +++-- cosmovisor/cmd/cosmovisor/cmd/run_config.go | 34 ++++++++ cosmovisor/cmd/cosmovisor/cmd/version.go | 78 +++++++++++++++---- cosmovisor/cmd/cosmovisor/main.go | 6 +- cosmovisor/errors/multi.go | 2 +- cosmovisor/logger.go | 7 +- cosmovisor/process.go | 68 +++++++++------- cosmovisor/process_test.go | 8 +- cosmovisor/scanner.go | 8 +- .../download/cosmovisor/genesis/bin/autod | 2 +- cosmovisor/upgrade.go | 7 +- cosmovisor/upgrade_test.go | 5 +- 17 files changed, 208 insertions(+), 89 deletions(-) create mode 100644 cosmovisor/cmd/cosmovisor/cmd/run_config.go diff --git a/cosmovisor/CHANGELOG.md b/cosmovisor/CHANGELOG.md index 5eb4e921ba..40dc5224e1 100644 --- a/cosmovisor/CHANGELOG.md +++ b/cosmovisor/CHANGELOG.md @@ -37,6 +37,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +* [\#11731](https://github.com/cosmos/cosmos-sdk/pull/11731) `cosmovisor version --json` returns the cosmovisor version and the result of `simd --output json --long` in one JSON object. + ## v1.1.0 2022-10-02 ### Features diff --git a/cosmovisor/args.go b/cosmovisor/args.go index f3643cdbdb..c9a0d36a92 100644 --- a/cosmovisor/args.go +++ b/cosmovisor/args.go @@ -11,11 +11,10 @@ import ( "strings" "time" - "github.com/rs/zerolog" - cverrors "github.com/cosmos/cosmos-sdk/cosmovisor/errors" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/rs/zerolog" ) // environment variable names @@ -184,11 +183,11 @@ func GetConfigFromEnv() (*Config, error) { } // LogConfigOrError logs either the config details or the error. -func LogConfigOrError(logger zerolog.Logger, cfg *Config, err error) { +func LogConfigOrError(logger *zerolog.Logger, cfg *Config, err error) { if cfg == nil && err == nil { return } - logger.Info().Msg("Configuration:") + logger.Info().Msg("configuration:") switch { case err != nil: cverrors.LogErrors(logger, "configuration errors found", err) @@ -227,9 +226,9 @@ func (cfg *Config) validate() []error { // if UnsafeSkipBackup is false, check if the DataBackupPath valid switch { case cfg.DataBackupPath == "": - errs = append(errs, errors.New(EnvDataBackupPath + " must not be empty")) + errs = append(errs, fmt.Errorf("%s must not be empty", EnvDataBackupPath)) case !filepath.IsAbs(cfg.DataBackupPath): - errs = append(errs, errors.New(cfg.DataBackupPath + " must be an absolute path")) + errs = append(errs, fmt.Errorf("%s must be an absolute path", cfg.DataBackupPath)) default: switch info, err := os.Stat(cfg.DataBackupPath); { case err != nil: @@ -281,9 +280,9 @@ func (cfg *Config) SetCurrentUpgrade(u upgradetypes.Plan) error { return f.Close() } -func (cfg *Config) UpgradeInfo() upgradetypes.Plan { +func (cfg *Config) UpgradeInfo() (upgradetypes.Plan, error) { if cfg.currentUpgrade.Name != "" { - return cfg.currentUpgrade + return cfg.currentUpgrade, nil } filename := filepath.Join(cfg.Root(), currentLink, upgradekeeper.UpgradeInfoFileName) @@ -300,12 +299,11 @@ func (cfg *Config) UpgradeInfo() upgradetypes.Plan { goto returnError } cfg.currentUpgrade = u - return cfg.currentUpgrade + return cfg.currentUpgrade, nil returnError: - Logger.Error().Err(err).Str("filename", filename).Msg("failed to read") cfg.currentUpgrade.Name = "_" - return cfg.currentUpgrade + return cfg.currentUpgrade, fmt.Errorf("failed to read %q: %w", filename, err) } // checks and validates env option diff --git a/cosmovisor/args_test.go b/cosmovisor/args_test.go index 67226df6dc..136440a632 100644 --- a/cosmovisor/args_test.go +++ b/cosmovisor/args_test.go @@ -570,9 +570,10 @@ func (s *argsTestSuite) TestLogConfigOrError() { } errMulti := errors.FlattenErrors(errs...) - makeTestLogger := func(testName string, out io.Writer) zerolog.Logger { + makeTestLogger := func(testName string, out io.Writer) *zerolog.Logger { output := zerolog.ConsoleWriter{Out: out, TimeFormat: time.Kitchen, NoColor: true} - return zerolog.New(output).With().Str("test", testName).Timestamp().Logger() + logger := zerolog.New(output).With().Str("test", testName).Timestamp().Logger() + return &logger } tests := []struct { diff --git a/cosmovisor/cmd/cosmovisor/cmd/help.go b/cosmovisor/cmd/cosmovisor/cmd/help.go index 701fadd2d2..780f32045e 100644 --- a/cosmovisor/cmd/cosmovisor/cmd/help.go +++ b/cosmovisor/cmd/cosmovisor/cmd/help.go @@ -17,9 +17,11 @@ func ShouldGiveHelp(arg string) bool { } // DoHelp outputs help text -func DoHelp() { +func DoHelp() error { // Not using the logger for this output because the header and footer look weird for help text. fmt.Println(GetHelpText()) + + return nil } // GetHelpText creates the help text multi-line string. diff --git a/cosmovisor/cmd/cosmovisor/cmd/root.go b/cosmovisor/cmd/cosmovisor/cmd/root.go index 2b1921ca56..759fe326f0 100644 --- a/cosmovisor/cmd/cosmovisor/cmd/root.go +++ b/cosmovisor/cmd/cosmovisor/cmd/root.go @@ -3,30 +3,34 @@ package cmd import ( "strings" - "github.com/cosmos/cosmos-sdk/cosmovisor" + "github.com/rs/zerolog" ) // RunCosmovisorCommand executes the desired cosmovisor command. -func RunCosmovisorCommand(args []string) error { +func RunCosmovisorCommand(logger *zerolog.Logger, args []string) error { arg0 := "" if len(args) > 0 { arg0 = strings.TrimSpace(args[0]) } + switch { case IsVersionCommand(arg0): - return PrintVersion() + return PrintVersion(logger, args[1:]) + case ShouldGiveHelp(arg0): - DoHelp() - return nil + return DoHelp() + case IsRunCommand(arg0): - return Run(args[1:]) + return Run(logger, args[1:]) } + warnRun := func() { - cosmovisor.Logger.Warn().Msg("Use of cosmovisor without the 'run' command is deprecated. Use: cosmovisor run [args]") + logger.Warn().Msg("use of cosmovisor without the 'run' command is deprecated. Use: cosmovisor run [args]") } warnRun() defer warnRun() - return Run(args) + + return Run(logger, args) } // isOneOf returns true if the given arg equals one of the provided options (ignoring case). diff --git a/cosmovisor/cmd/cosmovisor/cmd/run.go b/cosmovisor/cmd/cosmovisor/cmd/run.go index 8912e1a977..002c2a32a9 100644 --- a/cosmovisor/cmd/cosmovisor/cmd/run.go +++ b/cosmovisor/cmd/cosmovisor/cmd/run.go @@ -1,9 +1,8 @@ package cmd import ( - "os" - "github.com/cosmos/cosmos-sdk/cosmovisor" + "github.com/rs/zerolog" ) // RunArgs are the strings that indicate a cosmovisor run command. @@ -15,24 +14,30 @@ func IsRunCommand(arg string) bool { } // Run runs the configured program with the given args and monitors it for upgrades. -func Run(args []string) error { +func Run(logger *zerolog.Logger, args []string, options ...RunOption) error { cfg, err := cosmovisor.GetConfigFromEnv() if err != nil { return err } - launcher, err := cosmovisor.NewLauncher(cfg) + + runCfg := DefaultRunConfig + for _, opt := range options { + opt(&runCfg) + } + + launcher, err := cosmovisor.NewLauncher(logger, cfg) if err != nil { return err } - doUpgrade, err := launcher.Run(args, os.Stdout, os.Stderr) + doUpgrade, err := launcher.Run(args, runCfg.StdOut, runCfg.StdErr) // if RestartAfterUpgrade, we launch after a successful upgrade (only condition LaunchProcess returns nil) for cfg.RestartAfterUpgrade && err == nil && doUpgrade { - cosmovisor.Logger.Info().Str("app", cfg.Name).Msg("upgrade detected, relaunching") - doUpgrade, err = launcher.Run(args, os.Stdout, os.Stderr) + logger.Info().Str("app", cfg.Name).Msg("upgrade detected, relaunching") + doUpgrade, err = launcher.Run(args, runCfg.StdOut, runCfg.StdErr) } if doUpgrade && err == nil { - cosmovisor.Logger.Info().Msg("upgrade detected, DAEMON_RESTART_AFTER_UPGRADE is off. Verify new upgrade and start cosmovisor again.") + logger.Info().Msg("upgrade detected, DAEMON_RESTART_AFTER_UPGRADE is off. Verify new upgrade and start cosmovisor again.") } return err diff --git a/cosmovisor/cmd/cosmovisor/cmd/run_config.go b/cosmovisor/cmd/cosmovisor/cmd/run_config.go new file mode 100644 index 0000000000..ab84d3c307 --- /dev/null +++ b/cosmovisor/cmd/cosmovisor/cmd/run_config.go @@ -0,0 +1,34 @@ +package cmd + +import ( + "io" + "os" +) + +// DefaultRunConfig defintes a default RunConfig that writes to os.Stdout and os.Stderr +var DefaultRunConfig = RunConfig{ + StdOut: os.Stdout, + StdErr: os.Stderr, +} + +// RunConfig defines the configuration for running a command +type RunConfig struct { + StdOut io.Writer + StdErr io.Writer +} + +type RunOption func(*RunConfig) + +// StdOutRunOption sets the StdOut writer for the Run command +func StdOutRunOption(w io.Writer) RunOption { + return func(cfg *RunConfig) { + cfg.StdOut = w + } +} + +// SdErrRunOption sets the StdErr writer for the Run command +func StdErrRunOption(w io.Writer) RunOption { + return func(cfg *RunConfig) { + cfg.StdErr = w + } +} diff --git a/cosmovisor/cmd/cosmovisor/cmd/version.go b/cosmovisor/cmd/cosmovisor/cmd/version.go index 8f7e68f940..a341e19cf3 100644 --- a/cosmovisor/cmd/cosmovisor/cmd/version.go +++ b/cosmovisor/cmd/cosmovisor/cmd/version.go @@ -1,19 +1,24 @@ package cmd import ( + "encoding/json" "fmt" "os" + "strings" "time" cverrors "github.com/cosmos/cosmos-sdk/cosmovisor/errors" "github.com/rs/zerolog" ) -// Version represents Cosmovisor version value. Overwritten during build -var Version = "1.1.0" - -// VersionArgs is the strings that indicate a cosmovisor version command. -var VersionArgs = []string{"version", "--version"} +var ( + // FlagJSON formats the output in json + FlagJSON = "--json" + // Version represents Cosmovisor version value. Overwritten during build + Version = "1.1.0" + // VersionArgs is the strings that indicate a cosmovisor version command. + VersionArgs = []string{"version", "--version"} +) // IsVersionCommand checks if the given args indicate that the version is being requested. func IsVersionCommand(arg string) bool { @@ -21,16 +26,63 @@ func IsVersionCommand(arg string) bool { } // PrintVersion prints the cosmovisor version. -func PrintVersion() error { +func PrintVersion(logger *zerolog.Logger, args []string) error { + for _, arg := range args { + if strings.Contains(arg, FlagJSON) { + return printVersionJSON(logger, args) + } + } + + return printVersion(logger, args) +} + +func printVersion(logger *zerolog.Logger, args []string) error { fmt.Println("Cosmovisor Version: ", Version) - if err := Run([]string{"version"}); err != nil { - // Check the config and output details or any errors. - // Not using the cosmovisor.Logger in order to ignore any level it might have set, - // and also to not have any of the extra parameters in the output. - output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.Kitchen} - logger := zerolog.New(output).With().Timestamp().Logger() - cverrors.LogErrors(logger, "Can't run APP version", err) + if err := Run(logger, append([]string{"version"}, args...)); err != nil { + handleRunVersionFailure(err) } + return nil } + +func printVersionJSON(logger *zerolog.Logger, args []string) error { + buf := new(strings.Builder) + + // disable logger + l := logger.Level(zerolog.Disabled) + logger = &l + + if err := Run( + logger, + []string{"version", "--long", "--output", "json"}, + StdOutRunOption(buf), + ); err != nil { + handleRunVersionFailure(err) + } + + out, err := json.Marshal(struct { + Version string `json:"cosmovisor_version"` + AppVersion json.RawMessage `json:"app_version"` + }{ + Version: Version, + AppVersion: json.RawMessage(buf.String()), + }) + if err != nil { + l := logger.Level(zerolog.TraceLevel) + logger = &l + return fmt.Errorf("Can't print version output, expected valid json from APP, got: %s - %w", buf.String(), err) + } + + fmt.Println(string(out)) + return nil +} + +func handleRunVersionFailure(err error) { + // Check the config and output details or any errors. + // Not using the cosmovisor.Logger in order to ignore any level it might have set, + // and also to not have any of the extra parameters in the output. + output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.Kitchen} + logger := zerolog.New(output).With().Timestamp().Logger() + cverrors.LogErrors(&logger, "Can't run APP version", err) +} diff --git a/cosmovisor/cmd/cosmovisor/main.go b/cosmovisor/cmd/cosmovisor/main.go index 8cd8623c7e..e5a74966e0 100644 --- a/cosmovisor/cmd/cosmovisor/main.go +++ b/cosmovisor/cmd/cosmovisor/main.go @@ -9,9 +9,9 @@ import ( ) func main() { - cosmovisor.SetupLogging() - if err := cmd.RunCosmovisorCommand(os.Args[1:]); err != nil { - cverrors.LogErrors(cosmovisor.Logger, "", err) + logger := cosmovisor.NewLogger() + if err := cmd.RunCosmovisorCommand(logger, os.Args[1:]); err != nil { + cverrors.LogErrors(logger, "", err) os.Exit(1) } } diff --git a/cosmovisor/errors/multi.go b/cosmovisor/errors/multi.go index bb7885a9bb..d37212da2d 100644 --- a/cosmovisor/errors/multi.go +++ b/cosmovisor/errors/multi.go @@ -70,7 +70,7 @@ func (e MultiError) String() string { return e.Error() } -func LogErrors(logger zerolog.Logger, msg string, err error) { +func LogErrors(logger *zerolog.Logger, msg string, err error) { switch err := err.(type) { case *MultiError: if msg != "" { diff --git a/cosmovisor/logger.go b/cosmovisor/logger.go index cc7b58720d..ea7abac5c0 100644 --- a/cosmovisor/logger.go +++ b/cosmovisor/logger.go @@ -7,9 +7,8 @@ import ( "github.com/rs/zerolog" ) -var Logger zerolog.Logger - -func SetupLogging() { +func NewLogger() *zerolog.Logger { output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.Kitchen} - Logger = zerolog.New(output).With().Str("module", "cosmovisor").Timestamp().Logger() + logger := zerolog.New(output).With().Str("module", "cosmovisor").Timestamp().Logger() + return &logger } diff --git a/cosmovisor/process.go b/cosmovisor/process.go index 0f57940553..4087352de7 100644 --- a/cosmovisor/process.go +++ b/cosmovisor/process.go @@ -14,18 +14,24 @@ import ( "time" "github.com/otiai10/copy" + "github.com/rs/zerolog" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) type Launcher struct { - cfg *Config - fw *fileWatcher + logger *zerolog.Logger + cfg *Config + fw *fileWatcher } -func NewLauncher(cfg *Config) (Launcher, error) { - fw, err := newUpgradeFileWatcher(cfg.UpgradeInfoFilePath(), cfg.PollInterval) - return Launcher{cfg, fw}, err +func NewLauncher(logger *zerolog.Logger, cfg *Config) (Launcher, error) { + fw, err := newUpgradeFileWatcher(logger, cfg.UpgradeInfoFilePath(), cfg.PollInterval) + if err != nil { + return Launcher{}, err + } + + return Launcher{logger: logger, cfg: cfg, fw: fw}, nil } // Run launches the app in a subprocess and returns when the subprocess (app) @@ -40,7 +46,8 @@ func (l Launcher) Run(args []string, stdout, stderr io.Writer) (bool, error) { if err := EnsureBinary(bin); err != nil { return false, fmt.Errorf("current binary is invalid: %w", err) } - Logger.Info().Str("path", bin).Strs("args", args).Msg("running app") + + l.logger.Info().Str("path", bin).Strs("args", args).Msg("running app") cmd := exec.Command(bin, args...) cmd.Stdout = stdout cmd.Stderr = stderr @@ -53,7 +60,7 @@ func (l Launcher) Run(args []string, stdout, stderr io.Writer) (bool, error) { go func() { sig := <-sigs if err := cmd.Process.Signal(sig); err != nil { - Logger.Fatal().Err(err).Str("bin", bin).Msg("terminated") + l.logger.Fatal().Err(err).Str("bin", bin).Msg("terminated") } }() @@ -63,16 +70,16 @@ func (l Launcher) Run(args []string, stdout, stderr io.Writer) (bool, error) { } if !IsSkipUpgradeHeight(args, l.fw.currentInfo) { - if err := doBackup(l.cfg); err != nil { + if err := l.doBackup(); err != nil { return false, err } - if err = doPreUpgrade(l.cfg); err != nil { + if err = l.doPreUpgrade(); err != nil { return false, err } } - return true, DoUpgrade(l.cfg, l.fw.currentInfo) + return true, DoUpgrade(l.logger, l.cfg, l.fw.currentInfo) } // WaitForUpgradeOrExit checks upgrade plan file created by the app. @@ -83,7 +90,11 @@ func (l Launcher) Run(args []string, stdout, stderr io.Writer) (bool, error) { // It returns (false, nil) if the process exited normally without triggering an upgrade. This is very unlikely // to happened with "start" but may happened with short-lived commands like `gaiad export ...` func (l Launcher) WaitForUpgradeOrExit(cmd *exec.Cmd) (bool, error) { - currentUpgrade := l.cfg.UpgradeInfo() + currentUpgrade, err := l.cfg.UpgradeInfo() + if err != nil { + l.logger.Error().Err(err) + } + var cmdDone = make(chan error) go func() { cmdDone <- cmd.Wait() @@ -92,7 +103,7 @@ func (l Launcher) WaitForUpgradeOrExit(cmd *exec.Cmd) (bool, error) { select { case <-l.fw.MonitorUpdate(currentUpgrade): // upgrade - kill the process and restart - Logger.Info().Msg("Daemon shutting down in an attempt to restart") + l.logger.Info().Msg("daemon shutting down in an attempt to restart") _ = cmd.Process.Kill() case err := <-cmdDone: l.fw.Stop() @@ -109,12 +120,12 @@ func (l Launcher) WaitForUpgradeOrExit(cmd *exec.Cmd) (bool, error) { return true, nil } -func doBackup(cfg *Config) error { +func (l Launcher) doBackup() error { // take backup if `UNSAFE_SKIP_BACKUP` is not set. - if !cfg.UnsafeSkipBackup { + if !l.cfg.UnsafeSkipBackup { // check if upgrade-info.json is not empty. var uInfo upgradetypes.Plan - upgradeInfoFile, err := os.ReadFile(filepath.Join(cfg.Home, "data", "upgrade-info.json")) + upgradeInfoFile, err := os.ReadFile(filepath.Join(l.cfg.Home, "data", "upgrade-info.json")) if err != nil { return fmt.Errorf("error while reading upgrade-info.json: %w", err) } @@ -131,12 +142,12 @@ func doBackup(cfg *Config) error { // a destination directory, Format YYYY-MM-DD st := time.Now() stStr := fmt.Sprintf("%d-%d-%d", st.Year(), st.Month(), st.Day()) - dst := filepath.Join(cfg.DataBackupPath, fmt.Sprintf("data"+"-backup-%s", stStr)) + dst := filepath.Join(l.cfg.DataBackupPath, fmt.Sprintf("data"+"-backup-%s", stStr)) - Logger.Info().Time("backup start time", st).Msg("starting to take backup of data directory") + l.logger.Info().Time("backup start time", st).Msg("starting to take backup of data directory") // copy the $DAEMON_HOME/data to a backup dir - err = copy.Copy(filepath.Join(cfg.Home, "data"), dst) + err = copy.Copy(filepath.Join(l.cfg.Home, "data"), dst) if err != nil { return fmt.Errorf("error while taking data backup: %w", err) @@ -144,7 +155,7 @@ func doBackup(cfg *Config) error { // backup is done, lets check endtime to calculate total time taken for backup process et := time.Now() - Logger.Info().Str("backup saved at", dst).Time("backup completion time", et).TimeDiff("time taken to complete backup", et, st).Msg("backup completed") + l.logger.Info().Str("backup saved at", dst).Time("backup completion time", et).TimeDiff("time taken to complete backup", et, st).Msg("backup completed") } return nil @@ -152,38 +163,39 @@ func doBackup(cfg *Config) error { // doPreUpgrade runs the pre-upgrade command defined by the application and handles respective error codes // cfg contains the cosmovisor config from env var -func doPreUpgrade(cfg *Config) error { +func (l *Launcher) doPreUpgrade() error { counter := 0 for { - if counter > cfg.PreupgradeMaxRetries { - return fmt.Errorf("pre-upgrade command failed. reached max attempt of retries - %d", cfg.PreupgradeMaxRetries) + if counter > l.cfg.PreupgradeMaxRetries { + return fmt.Errorf("pre-upgrade command failed. reached max attempt of retries - %d", l.cfg.PreupgradeMaxRetries) } - err := executePreUpgradeCmd(cfg) + err := l.executePreUpgradeCmd() counter += 1 if err != nil { if err.(*exec.ExitError).ProcessState.ExitCode() == 1 { - Logger.Info().Msg("pre-upgrade command does not exist. continuing the upgrade.") + l.logger.Info().Msg("pre-upgrade command does not exist. continuing the upgrade.") return nil } if err.(*exec.ExitError).ProcessState.ExitCode() == 30 { return fmt.Errorf("pre-upgrade command failed : %w", err) } if err.(*exec.ExitError).ProcessState.ExitCode() == 31 { - Logger.Error().Err(err).Int("attempt", counter).Msg("pre-upgrade command failed. retrying") + l.logger.Error().Err(err).Int("attempt", counter).Msg("pre-upgrade command failed. retrying") continue } } - fmt.Println("pre-upgrade successful. continuing the upgrade.") + + l.logger.Info().Msg("pre-upgrade successful. continuing the upgrade.") return nil } } // executePreUpgradeCmd runs the pre-upgrade command defined by the application // cfg contains the cosmosvisor config from the env vars -func executePreUpgradeCmd(cfg *Config) error { - bin, err := cfg.CurrentBin() +func (l *Launcher) executePreUpgradeCmd() error { + bin, err := l.cfg.CurrentBin() if err != nil { return err } diff --git a/cosmovisor/process_test.go b/cosmovisor/process_test.go index b0c5ceb88a..31e948472b 100644 --- a/cosmovisor/process_test.go +++ b/cosmovisor/process_test.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package cosmovisor_test @@ -28,6 +29,7 @@ func (s *processTestSuite) TestLaunchProcess() { require := s.Require() home := copyTestData(s.T(), "validate") cfg := &cosmovisor.Config{Home: home, Name: "dummyd", PollInterval: 20, UnsafeSkipBackup: true} + logger := cosmovisor.NewLogger() // should run the genesis binary and produce expected output var stdout, stderr = NewBuffer(), NewBuffer() @@ -35,10 +37,11 @@ func (s *processTestSuite) TestLaunchProcess() { require.NoError(err) require.Equal(cfg.GenesisBin(), currentBin) - launcher, err := cosmovisor.NewLauncher(cfg) + launcher, err := cosmovisor.NewLauncher(logger, cfg) require.NoError(err) upgradeFile := cfg.UpgradeInfoFilePath() + args := []string{"foo", "bar", "1234", upgradeFile} doUpgrade, err := launcher.Run(args, stdout, stderr) require.NoError(err) @@ -77,6 +80,7 @@ func (s *processTestSuite) TestLaunchProcessWithDownloads() { require := s.Require() home := copyTestData(s.T(), "download") cfg := &cosmovisor.Config{Home: home, Name: "autod", AllowDownloadBinaries: true, PollInterval: 100, UnsafeSkipBackup: true} + logger := cosmovisor.NewLogger() upgradeFilename := cfg.UpgradeInfoFilePath() // should run the genesis binary and produce expected output @@ -84,7 +88,7 @@ func (s *processTestSuite) TestLaunchProcessWithDownloads() { require.NoError(err) require.Equal(cfg.GenesisBin(), currentBin) - launcher, err := cosmovisor.NewLauncher(cfg) + launcher, err := cosmovisor.NewLauncher(logger, cfg) require.NoError(err) var stdout, stderr = NewBuffer(), NewBuffer() diff --git a/cosmovisor/scanner.go b/cosmovisor/scanner.go index 255f737d44..7ed696f481 100644 --- a/cosmovisor/scanner.go +++ b/cosmovisor/scanner.go @@ -10,9 +10,12 @@ import ( "time" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/rs/zerolog" ) type fileWatcher struct { + logger *zerolog.Logger + // full path to a watched file filename string interval time.Duration @@ -26,7 +29,7 @@ type fileWatcher struct { initialized bool } -func newUpgradeFileWatcher(filename string, interval time.Duration) (*fileWatcher, error) { +func newUpgradeFileWatcher(logger *zerolog.Logger, filename string, interval time.Duration) (*fileWatcher, error) { if filename == "" { return nil, errors.New("filename undefined") } @@ -44,6 +47,7 @@ func newUpgradeFileWatcher(filename string, interval time.Duration) (*fileWatche } return &fileWatcher{ + logger: logger, filename: filenameAbs, interval: interval, currentInfo: upgradetypes.Plan{}, @@ -106,7 +110,7 @@ func (fw *fileWatcher) CheckUpdate(currentUpgrade upgradetypes.Plan) bool { info, err := parseUpgradeInfoFile(fw.filename) if err != nil { - Logger.Fatal().Err(err).Msg("failed to parse upgrade info file") + fw.logger.Fatal().Err(err).Msg("failed to parse upgrade info file") return false } diff --git a/cosmovisor/testdata/download/cosmovisor/genesis/bin/autod b/cosmovisor/testdata/download/cosmovisor/genesis/bin/autod index dd0a2c8751..89cb77365a 100755 --- a/cosmovisor/testdata/download/cosmovisor/genesis/bin/autod +++ b/cosmovisor/testdata/download/cosmovisor/genesis/bin/autod @@ -6,7 +6,7 @@ echo 'ERROR: UPGRADE "chain2" NEEDED at height: 49: zip_binary' # create upgrade info # this info contains directly information about binaries (in chain2->chain3 update we test with info containing a link to the file with an address for the new chain binary) -echo '{"name":"chain2","height":49,"info":"{\"binaries\":{\"linux/amd64\":\"https://github.com/cosmos/cosmos-sdk/raw/main/cosmovisor/testdata/repo/chain2-zip_bin/autod.zip?checksum=sha256:e2e178953d176196dcf736afa821121b259697ab4df90582044c313bcae48f13\"}}"}' >$3 +echo '{"name":"chain2","height":49,"info":"{\"binaries\":{\"linux/amd64\":\"https://github.com/cosmos/cosmos-sdk/raw/main/cosmovisor/testdata/repo/chain2-zip_bin/autod.zip?checksum=sha256:b30cf0b1a3e46ac9587cc4d7b102eb796e39e3e0dfa3f8ca6e163fc1b1e913ca\"}}"}' >$3 sleep 0.1 echo Never should be printed!!! diff --git a/cosmovisor/upgrade.go b/cosmovisor/upgrade.go index d9f44de32c..a3e5960ffe 100644 --- a/cosmovisor/upgrade.go +++ b/cosmovisor/upgrade.go @@ -13,12 +13,13 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/hashicorp/go-getter" "github.com/otiai10/copy" + "github.com/rs/zerolog" ) // DoUpgrade will be called after the log message has been parsed and the process has terminated. // We can now make any changes to the underlying directory without interference and leave it // in a state, so we can make a proper restart -func DoUpgrade(cfg *Config, info upgradetypes.Plan) error { +func DoUpgrade(logger *zerolog.Logger, cfg *Config, info upgradetypes.Plan) error { // Simplest case is to switch the link err := EnsureBinary(cfg.UpgradeBin(info.Name)) if err == nil { @@ -36,11 +37,11 @@ func DoUpgrade(cfg *Config, info upgradetypes.Plan) error { } // If not there, then we try to download it... maybe - Logger.Info().Msg("No upgrade binary found, beginning to download it") + logger.Info().Msg("no upgrade binary found, beginning to download it") if err := DownloadBinary(cfg, info); err != nil { return fmt.Errorf("cannot download binary. %w", err) } - Logger.Info().Msg("Downloading binary complete") + logger.Info().Msg("downloading binary complete") // and then set the binary again if err := EnsureBinary(cfg.UpgradeBin(info.Name)); err != nil { diff --git a/cosmovisor/upgrade_test.go b/cosmovisor/upgrade_test.go index 71eb300a9b..44a611222d 100644 --- a/cosmovisor/upgrade_test.go +++ b/cosmovisor/upgrade_test.go @@ -95,6 +95,7 @@ func (s *upgradeTestSuite) assertCurrentLink(cfg cosmovisor.Config, target strin func (s *upgradeTestSuite) TestDoUpgradeNoDownloadUrl() { home := copyTestData(s.T(), "validate") cfg := &cosmovisor.Config{Home: home, Name: "dummyd", AllowDownloadBinaries: true} + logger := cosmovisor.NewLogger() currentBin, err := cfg.CurrentBin() s.Require().NoError(err) @@ -104,7 +105,7 @@ func (s *upgradeTestSuite) TestDoUpgradeNoDownloadUrl() { // do upgrade ignores bad files for _, name := range []string{"missing", "nobin", "noexec"} { info := upgradetypes.Plan{Name: name} - err = cosmovisor.DoUpgrade(cfg, info) + err = cosmovisor.DoUpgrade(logger, cfg, info) s.Require().Error(err, name) currentBin, err := cfg.CurrentBin() s.Require().NoError(err) @@ -115,7 +116,7 @@ func (s *upgradeTestSuite) TestDoUpgradeNoDownloadUrl() { for _, upgrade := range []string{"chain2", "chain3"} { // now set it to a valid upgrade and make sure CurrentBin is now set properly info := upgradetypes.Plan{Name: upgrade} - err = cosmovisor.DoUpgrade(cfg, info) + err = cosmovisor.DoUpgrade(logger, cfg, info) s.Require().NoError(err) // we should see current point to the new upgrade dir upgradeBin := cfg.UpgradeBin(upgrade)