feat(cosmovisor): Cosmovisor upgrade plan without automatic lower case (#16919)

This commit is contained in:
Chill Validation 2023-07-12 17:56:56 +09:00 committed by GitHub
parent 1b0fcdc9f0
commit c5df6a355a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 187 additions and 80 deletions

View File

@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
## Improvements
* [#16919](https://github.com/cosmos/cosmos-sdk/pull/16919) Add COSMOVISOR_DISABLE_RECASE to cosmovisor to disable automatic case change for plan name
* [#14881](https://github.com/cosmos/cosmos-sdk/pull/14881) Refactor Cosmovisor to use `x/upgrade` validation logic.
* [#14881](https://github.com/cosmos/cosmos-sdk/pull/14881) Refactor Cosmovisor to depend only on the `x/upgrade` module.
* [#15362](https://github.com/cosmos/cosmos-sdk/pull/15362) Allow disabling Cosmovisor logs

View File

@ -98,6 +98,7 @@ Use of `cosmovisor` without one of the action arguments is deprecated. For backw
* `COSMOVISOR_COLOR_LOGS` (defaults to `true`). If set to true, this will colorise Cosmovisor logs (but not the underlying process).
* `COSMOVISOR_TIMEFORMAT_LOGS` (defaults to `kitchen`). If set to a value (`layout|ansic|unixdate|rubydate|rfc822|rfc822z|rfc850|rfc1123|rfc1123z|rfc3339|rfc3339nano|kitchen`), this will add timestamp prefix to Cosmovisor logs (but not the underlying process).
* `COSMOVISOR_CUSTOM_PREUPGRADE` (defaults to ``). If set, this will run $DAEMON_HOME/cosmovisor/$COSMOVISOR_CUSTOM_PREUPGRADE prior to upgrade with the arguments [ upgrade.Name, upgrade.Height ]. Executes a custom script (separate and prior to the chain daemon pre-upgrade command)
* `COSMOVISOR_DISABLE_RECASE` (defaults to `false`). If set to true, the upgrade directory will expected to match the upgrade plan name without any case changes
### Folder Layout

View File

@ -33,6 +33,7 @@ const (
EnvColorLogs = "COSMOVISOR_COLOR_LOGS"
EnvTimeFormatLogs = "COSMOVISOR_TIMEFORMAT_LOGS"
EnvCustomPreupgrade = "COSMOVISOR_CUSTOM_PREUPGRADE"
EnvDisableRecase = "COSMOVISOR_DISABLE_RECASE"
)
const (
@ -58,6 +59,7 @@ type Config struct {
ColorLogs bool
TimeFormatLogs string
CustomPreupgrade string
DisableRecase bool
// currently running upgrade
currentUpgrade upgradetypes.Plan
@ -178,6 +180,9 @@ func GetConfigFromEnv() (*Config, error) {
if cfg.TimeFormatLogs, err = TimeFormatOptionFromEnv(EnvTimeFormatLogs, time.Kitchen); err != nil {
errs = append(errs, err)
}
if cfg.DisableRecase, err = BooleanOption(EnvDisableRecase, false); err != nil {
errs = append(errs, err)
}
interval := os.Getenv(EnvInterval)
if interval != "" {

View File

@ -38,6 +38,7 @@ type cosmovisorEnv struct {
ColorLogs string
TimeFormatLogs string
CustomPreupgrade string
DisableRecase string
}
type envMap struct {
@ -62,6 +63,7 @@ func (c cosmovisorEnv) ToMap() map[string]envMap {
EnvColorLogs: {val: c.ColorLogs, allowEmpty: false},
EnvTimeFormatLogs: {val: c.TimeFormatLogs, allowEmpty: true},
EnvCustomPreupgrade: {val: c.CustomPreupgrade, allowEmpty: true},
EnvDisableRecase: {val: c.DisableRecase, allowEmpty: true},
}
}
@ -96,6 +98,8 @@ func (c *cosmovisorEnv) Set(envVar, envVal string) {
c.TimeFormatLogs = envVal
case EnvCustomPreupgrade:
c.CustomPreupgrade = envVal
case EnvDisableRecase:
c.DisableRecase = envVal
default:
panic(fmt.Errorf("Unknown environment variable [%s]. Ccannot set field to [%s]. ", envVar, envVal))
}
@ -456,6 +460,7 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
disableLogs, colorLogs bool,
timeFormatLogs string,
customPreUpgrade string,
disableRecase bool,
) *Config {
return &Config{
Home: home,
@ -472,6 +477,7 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
ColorLogs: colorLogs,
TimeFormatLogs: timeFormatLogs,
CustomPreupgrade: customPreUpgrade,
DisableRecase: disableRecase,
}
}
@ -495,19 +501,21 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
Interval: "bad",
PreupgradeMaxRetries: "bad",
TimeFormatLogs: "bad",
CustomPreupgrade: "",
DisableRecase: "bad",
},
expectedCfg: nil,
expectedErrCount: 11,
expectedErrCount: 12,
},
{
name: "all good",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", "true"},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", true),
expectedErrCount: 0,
},
{
name: "nothing set",
envVals: cosmovisorEnv{"", "", "", "", "", "", "", "", "", "", "false", "false", "", ""},
envVals: cosmovisorEnv{"", "", "", "", "", "", "", "", "", "", "false", "false", "", "", ""},
expectedCfg: nil,
expectedErrCount: 3,
},
@ -515,220 +523,231 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
// timeformat tests are done in the TestTimeFormat
{
name: "download bin bad",
envVals: cosmovisorEnv{absPath, "testname", "bad", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", ""},
envVals: cosmovisorEnv{absPath, "testname", "bad", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "download bin not set",
envVals: cosmovisorEnv{absPath, "testname", "", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, ""),
envVals: cosmovisorEnv{absPath, "testname", "", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "", false),
expectedErrCount: 0,
},
{
name: "download bin true",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "download bin false",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "download ensure checksum true",
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, false, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", true, false, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "restart upgrade bad",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "bad", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "bad", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart upgrade not set",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, true, true, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", true, true, true, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "restart upgrade true",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "true", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, true, true, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "true", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", true, true, true, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "restart upgrade true",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "skip unsafe backups bad",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "bad", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "bad", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "skip unsafe backups not set",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, false, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, false, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "skip unsafe backups true",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "true", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, true, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "skip unsafe backups false",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "false", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, false, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "false", "600ms", "false", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", true, true, false, 600, false, absPath, 303, 1, false, true, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "poll interval bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "bad", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "bad", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "poll interval 0",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "0", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "0", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "poll interval not set",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "", "1", "false", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 300, 1, false, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "", "1", "false", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 300, 1, false, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "poll interval 600",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "600", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "600", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "poll interval 1s",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "1s", "1", "false", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 1000, 1, false, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "1s", "1", "false", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 1000, 1, false, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "poll interval -3m",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "-3m", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "-3m", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart delay bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "bad", "false", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "bad", "false", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart delay 0",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "0", "false", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "0", "false", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart delay not set",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "", "false", "", "303ms", "1", "false", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 0, false, absPath, 303, 1, false, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "", "false", "", "303ms", "1", "false", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 0, false, absPath, 303, 1, false, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "restart delay 600",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600", "false", "", "300ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600", "false", "", "300ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart delay 1s",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "1s", "false", "", "303ms", "1", "false", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 1000, false, absPath, 303, 1, false, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "1s", "false", "", "303ms", "1", "false", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 1000, false, absPath, 303, 1, false, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "restart delay -3m",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "-3m", "false", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "-3m", "false", "", "303ms", "1", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "prepupgrade max retries bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "bad", "false", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "bad", "false", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "prepupgrade max retries 0",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "0", "false", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, false, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "0", "false", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, false, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "prepupgrade max retries not set",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "false", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, false, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "false", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, false, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "prepupgrade max retries 5",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "5", "false", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 5, false, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "5", "false", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 5, false, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "disable logs bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "5", "bad", "true", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "5", "bad", "true", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "disable logs good",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "disable logs color bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "5", "true", "bad", "kitchen", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "5", "true", "bad", "kitchen", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "disable logs color good",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "false", "kitchen", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, false, time.Kitchen, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "false", "kitchen", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, false, time.Kitchen, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "disable logs timestamp",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "false", "", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, false, "", "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "false", "", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, false, "", "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "enable rf3339 logs timestamp",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "true", "rfc3339", "preupgrade.sh"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, true, time.RFC3339, "preupgrade.sh"),
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "true", "rfc3339", "preupgrade.sh", ""},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, true, time.RFC3339, "preupgrade.sh", false),
expectedErrCount: 0,
},
{
name: "invalid logs timestamp format",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "true", "invalid", "preupgrade.sh"},
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "true", "invalid", "preupgrade.sh", ""},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "disable recase good",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "true", "rfc3339", "preupgrade.sh", "true"},
expectedCfg: newConfig(absPath, "testname", false, true, false, 600, false, absPath, 406, 0, true, true, time.RFC3339, "preupgrade.sh", true),
expectedErrCount: 0,
},
{
name: "disable recase bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "true", "false", "600ms", "false", "", "406ms", "", "true", "true", "rfc3339", "preupgrade.sh", "bad"},
expectedErrCount: 1,
},
}
for _, tc := range tests {

View File

@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
"github.com/spf13/cobra"
@ -37,9 +38,9 @@ func AddUpgrade(cmd *cobra.Command, args []string) error {
logger := cfg.Logger(os.Stdout)
upgradeName := strings.ToLower(args[0])
if len(upgradeName) == 0 {
return fmt.Errorf("upgrade name cannot be empty")
upgradeName := args[0]
if !cfg.DisableRecase {
upgradeName = strings.ToLower(args[0])
}
executablePath := args[1]
@ -93,7 +94,7 @@ func AddUpgrade(cmd *cobra.Command, args []string) error {
return err
}
logger.Info(fmt.Sprintf("%s created, %s upgrade binary will switch at height %d", upgradetypes.UpgradeInfoFilename, upgradeName, upgradeHeight))
logger.Info(fmt.Sprintf("%s created, %s upgrade binary will switch at height %d", filepath.Join(cfg.UpgradeInfoFilePath(), upgradetypes.UpgradeInfoFilename), upgradeName, upgradeHeight))
}
return nil

View File

@ -74,6 +74,51 @@ func (s *processTestSuite) TestLaunchProcess() {
require.Equal(cfg.UpgradeBin("chain2"), currentBin)
}
// TestPlanDisableRecase will test upgrades without lower case plan names
func (s *processTestSuite) TestPlanDisableRecase() {
// binaries from testdata/validate directory
require := s.Require()
home := copyTestData(s.T(), "norecase")
cfg := &cosmovisor.Config{Home: home, Name: "dummyd", PollInterval: 20, UnsafeSkipBackup: true, DisableRecase: true}
logger := log.NewTestLogger(s.T()).With(log.ModuleKey, "cosmosvisor")
// should run the genesis binary and produce expected output
stdout, stderr := newBuffer(), newBuffer()
currentBin, err := cfg.CurrentBin()
require.NoError(err)
require.Equal(cfg.GenesisBin(), currentBin)
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)
require.True(doUpgrade)
require.Equal("", stderr.String())
require.Equal(fmt.Sprintf("Genesis foo bar 1234 %s\nUPGRADE \"Chain2\" NEEDED at height: 49: {}\n", upgradeFile), stdout.String())
// ensure this is upgraded now and produces new output
currentBin, err = cfg.CurrentBin()
require.NoError(err)
require.Equal(cfg.UpgradeBin("Chain2"), currentBin)
args = []string{"second", "run", "--verbose"}
stdout.Reset()
stderr.Reset()
doUpgrade, err = launcher.Run(args, stdout, stderr)
require.NoError(err)
require.False(doUpgrade)
require.Equal("", stderr.String())
require.Equal("Chain 2 is live!\nArgs: second run --verbose\nFinished successfully\n", stdout.String())
// ended without other upgrade
require.Equal(cfg.UpgradeBin("Chain2"), currentBin)
}
func (s *processTestSuite) TestLaunchProcessWithRestartDelay() {
// binaries from testdata/validate directory
require := s.Require()

View File

@ -25,8 +25,9 @@ type fileWatcher struct {
cancel chan bool
ticker *time.Ticker
needsUpdate bool
initialized bool
needsUpdate bool
initialized bool
disableRecase bool
}
func newUpgradeFileWatcher(cfg *Config, logger log.Logger) (*fileWatcher, error) {
@ -51,15 +52,16 @@ func newUpgradeFileWatcher(cfg *Config, logger log.Logger) (*fileWatcher, error)
}
return &fileWatcher{
currentBin: bin,
filename: filenameAbs,
interval: cfg.PollInterval,
currentInfo: upgradetypes.Plan{},
lastModTime: time.Time{},
cancel: make(chan bool),
ticker: time.NewTicker(cfg.PollInterval),
needsUpdate: false,
initialized: false,
currentBin: bin,
filename: filenameAbs,
interval: cfg.PollInterval,
currentInfo: upgradetypes.Plan{},
lastModTime: time.Time{},
cancel: make(chan bool),
ticker: time.NewTicker(cfg.PollInterval),
needsUpdate: false,
initialized: false,
disableRecase: cfg.DisableRecase,
}, nil
}
@ -112,7 +114,7 @@ func (fw *fileWatcher) CheckUpdate(currentUpgrade upgradetypes.Plan) bool {
return false
}
info, err := parseUpgradeInfoFile(fw.filename)
info, err := parseUpgradeInfoFile(fw.filename, fw.disableRecase)
if err != nil {
panic(fmt.Errorf("failed to parse upgrade info file: %w", err))
}
@ -180,7 +182,7 @@ func (fw *fileWatcher) checkHeight() (int64, error) {
return strconv.ParseInt(resp.SyncInfo.LatestBlockHeight, 10, 64)
}
func parseUpgradeInfoFile(filename string) (upgradetypes.Plan, error) {
func parseUpgradeInfoFile(filename string, disableRecase bool) (upgradetypes.Plan, error) {
f, err := os.ReadFile(filename)
if err != nil {
return upgradetypes.Plan{}, err
@ -201,7 +203,9 @@ func parseUpgradeInfoFile(filename string) (upgradetypes.Plan, error) {
}
// normalize name to prevent operator error in upgrade name case sensitivity errors.
upgradePlan.Name = strings.ToLower(upgradePlan.Name)
if !disableRecase {
upgradePlan.Name = strings.ToLower(upgradePlan.Name)
}
return upgradePlan, err
}

View File

@ -13,50 +13,66 @@ func TestParseUpgradeInfoFile(t *testing.T) {
cases := []struct {
filename string
expectUpgrade upgradetypes.Plan
disableRecase bool
expectErr bool
}{
{
filename: "f1-good.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{Name: "upgrade1", Info: "some info", Height: 123},
expectErr: false,
},
{
filename: "f2-normalized-name.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{Name: "upgrade2", Info: "some info", Height: 125},
expectErr: false,
},
{
filename: "f2-normalized-name.json",
disableRecase: true,
expectUpgrade: upgradetypes.Plan{Name: "Upgrade2", Info: "some info", Height: 125},
expectErr: false,
},
{
filename: "f2-bad-type.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{},
expectErr: true,
},
{
filename: "f2-bad-type-2.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{},
expectErr: true,
},
{
filename: "f3-empty.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{},
expectErr: true,
},
{
filename: "f4-empty-obj.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{},
expectErr: true,
},
{
filename: "f5-partial-obj-1.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{},
expectErr: true,
},
{
filename: "f5-partial-obj-2.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{},
expectErr: true,
},
{
filename: "unknown.json",
disableRecase: false,
expectUpgrade: upgradetypes.Plan{},
expectErr: true,
},
@ -66,7 +82,7 @@ func TestParseUpgradeInfoFile(t *testing.T) {
tc := cases[i]
t.Run(tc.filename, func(t *testing.T) {
require := require.New(t)
ui, err := parseUpgradeInfoFile(filepath.Join(".", "testdata", "upgrade-files", tc.filename))
ui, err := parseUpgradeInfoFile(filepath.Join(".", "testdata", "upgrade-files", tc.filename), tc.disableRecase)
if tc.expectErr {
require.Error(err)
} else {

View File

@ -0,0 +1,9 @@
#!/bin/sh
echo Genesis $@
sleep 1
test -z $4 && exit 1001
echo 'UPGRADE "Chain2" NEEDED at height: 49: {}'
echo '{"name":"Chain2","height":49,"info":""}' > $4
sleep 2
echo Never should be printed!!!

View File

@ -0,0 +1,6 @@
#!/bin/sh
echo Chain 2 is live!
echo Args: $@
sleep 1
echo Finished successfully

View File