fix(cosmovisor): let cosmovisor version return a valid json (#11731)
This commit is contained in:
parent
1d8a878728
commit
019444ae43
@ -37,6 +37,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
## [Unreleased]
|
||||
<!-- NOTE: when creating a new release, update cosmovisor/cmd/cosmovisor/cmd/version.go:Version -->
|
||||
|
||||
* [\#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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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).
|
||||
|
||||
@ -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
|
||||
|
||||
34
cosmovisor/cmd/cosmovisor/cmd/run_config.go
Normal file
34
cosmovisor/cmd/cosmovisor/cmd/run_config.go
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 != "" {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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!!!
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user