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

refactor: cosmovisor name normalization & comparison #11608

Merged
merged 6 commits into from
Apr 13, 2022
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
8 changes: 4 additions & 4 deletions cosmovisor/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@ go 1.17

require (
github.com/cosmos/cosmos-sdk v0.46.0-beta2
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.5.11
github.com/otiai10/copy v1.7.0
github.com/rs/zerolog v1.26.1
github.com/stretchr/testify v1.7.1
google.golang.org/api v0.63.0 // indirect
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

require (
Expand Down Expand Up @@ -57,6 +53,7 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.2.1 // indirect
Expand Down Expand Up @@ -111,11 +108,14 @@ require (
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/api v0.63.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.66.3 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

Expand Down
60 changes: 45 additions & 15 deletions cosmovisor/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
Expand All @@ -29,18 +30,29 @@ func newUpgradeFileWatcher(filename string, interval time.Duration) (*fileWatche
if filename == "" {
return nil, errors.New("filename undefined")
}

filenameAbs, err := filepath.Abs(filename)
if err != nil {
return nil,
fmt.Errorf("wrong path, %s must be a valid file path, [%w]", filename, err)
fmt.Errorf("invalid path; %s must be a valid file path: %w", filename, err)
}

dirname := filepath.Dir(filename)
info, err := os.Stat(dirname)
if err != nil || !info.IsDir() {
return nil, fmt.Errorf("wrong path, %s must be an existing directory, [%w]", dirname, err)
return nil, fmt.Errorf("invalid path; %s must be an existing directory: %w", dirname, err)
}

return &fileWatcher{filenameAbs, interval, upgradetypes.Plan{}, time.Time{}, make(chan bool), time.NewTicker(interval), false, false}, nil
return &fileWatcher{
filename: filenameAbs,
interval: interval,
currentInfo: upgradetypes.Plan{},
lastModTime: time.Time{},
cancel: make(chan bool),
ticker: time.NewTicker(interval),
needsUpdate: false,
initialized: false,
}, nil
}

func (fw *fileWatcher) Stop() {
Expand All @@ -64,11 +76,13 @@ func (fw *fileWatcher) MonitorUpdate(currentUpgrade upgradetypes.Plan) <-chan st
done <- struct{}{}
return
}

case <-fw.cancel:
return
}
}
}()

return done
}

Expand All @@ -79,25 +93,33 @@ func (fw *fileWatcher) CheckUpdate(currentUpgrade upgradetypes.Plan) bool {
if fw.needsUpdate {
return true
}

stat, err := os.Stat(fw.filename)
if err != nil { // file doesn't exists
if err != nil {
// file doesn't exists
return false
}

if !stat.ModTime().After(fw.lastModTime) {
return false
}

info, err := parseUpgradeInfoFile(fw.filename)
if err != nil {
Logger.Fatal().Err(err).Msg("Can't parse upgrade info file")
Logger.Fatal().Err(err).Msg("failed to parse upgrade info file")
return false
}
if !fw.initialized { // daemon has restarted

if !fw.initialized {
// daemon has restarted
fw.initialized = true
fw.currentInfo = info
fw.lastModTime = stat.ModTime()
// heuristic: deamon has restarted, so we don't know if we successfully downloaded the upgrade or not.
// so we try to compare the running upgrade name (read from the cosmovisor file) with the upgrade info
if currentUpgrade.Name != fw.currentInfo.Name {

// Heuristic: Deamon has restarted, so we don't know if we successfully
// downloaded the upgrade or not. So we try to compare the running upgrade
// name (read from the cosmovisor file) with the upgrade info.
if !strings.EqualFold(currentUpgrade.Name, fw.currentInfo.Name) {
fw.needsUpdate = true
return true
}
Expand All @@ -109,24 +131,32 @@ func (fw *fileWatcher) CheckUpdate(currentUpgrade upgradetypes.Plan) bool {
fw.needsUpdate = true
return true
}

return false
}

func parseUpgradeInfoFile(filename string) (upgradetypes.Plan, error) {
var ui upgradetypes.Plan

f, err := os.Open(filename)
if err != nil {
return ui, err
return upgradetypes.Plan{}, err
}
defer f.Close()

d := json.NewDecoder(f)
err = d.Decode(&ui)
if err != nil {
return ui, err
if err := d.Decode(&ui); err != nil {
return upgradetypes.Plan{}, err
}

// required values must be set
if ui.Height == 0 || ui.Name == "" {
return upgradetypes.Plan{}, fmt.Errorf("invalid upgrade-info.json content. Name and Hight must be not empty. Got: %v", ui)
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
if ui.Height <= 0 || ui.Name == "" {
return upgradetypes.Plan{}, fmt.Errorf("invalid upgrade-info.json content; name and height must be not empty; got: %v", ui)
}

// Normalize name to prevent operator error in upgrade name case sensitivity
// errors.
ui.Name = strings.ToLower(ui.Name)

return ui, err
}
3 changes: 1 addition & 2 deletions cosmovisor/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import (
"runtime"
"strings"

upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
"github.com/hashicorp/go-getter"
"github.com/otiai10/copy"

upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)

// DoUpgrade will be called after the log message has been parsed and the process has terminated.
Expand Down