refactor: make cosmovisor depend on x/upgrade only (#14881)
This commit is contained in:
parent
12394c8b99
commit
b3724f1a0d
@ -36,6 +36,15 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## Client Breaking Changes
|
||||
|
||||
* [#14881](https://github.com/cosmos/cosmos-sdk/pull/14881) Cosmovisor supports only upgrade plan with a checksum. This is enforced by the `x/upgrade` module for better security.
|
||||
|
||||
## Improvements
|
||||
|
||||
* [#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.
|
||||
|
||||
## v1.4.0 2022-10-23
|
||||
|
||||
### API Breaking Changes
|
||||
|
||||
@ -11,8 +11,9 @@ import (
|
||||
"time"
|
||||
|
||||
cverrors "cosmossdk.io/tools/cosmovisor/errors"
|
||||
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
upgradekeeper "cosmossdk.io/x/upgrade/keeper"
|
||||
"cosmossdk.io/x/upgrade/plan"
|
||||
upgradetypes "cosmossdk.io/x/upgrade/types"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
@ -275,7 +276,7 @@ func (cfg *Config) SetCurrentUpgrade(u upgradetypes.Plan) (rerr error) {
|
||||
// ensure named upgrade exists
|
||||
bin := cfg.UpgradeBin(u.Name)
|
||||
|
||||
if err := EnsureBinary(bin); err != nil {
|
||||
if err := plan.EnsureBinary(bin); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/tools/cosmovisor/errors"
|
||||
"cosmossdk.io/x/upgrade/plan"
|
||||
)
|
||||
|
||||
type argsTestSuite struct {
|
||||
@ -250,20 +251,19 @@ func (s *argsTestSuite) TestEnsureBin() {
|
||||
cfg := Config{Home: absPath, Name: "dummyd", DataBackupPath: absPath}
|
||||
s.Require().Len(cfg.validate(), 0, "validation errors")
|
||||
|
||||
s.Require().NoError(EnsureBinary(cfg.GenesisBin()))
|
||||
s.Require().NoError(plan.EnsureBinary(cfg.GenesisBin()))
|
||||
|
||||
cases := map[string]struct {
|
||||
upgrade string
|
||||
hasBin bool
|
||||
}{
|
||||
"proper": {"chain2", true},
|
||||
"no binary": {"nobin", false},
|
||||
"not executable": {"noexec", false},
|
||||
"no directory": {"foobarbaz", false},
|
||||
"proper": {"chain2", true},
|
||||
"no binary": {"nobin", false},
|
||||
"no directory": {"foobarbaz", false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := EnsureBinary(cfg.UpgradeBin(tc.upgrade))
|
||||
err := plan.EnsureBinary(cfg.UpgradeBin(tc.upgrade))
|
||||
if tc.hasBin {
|
||||
s.Require().NoError(err)
|
||||
} else {
|
||||
|
||||
@ -18,7 +18,7 @@ the proposal. Cosmovisor interprets that data to perform an update: switch a cur
|
||||
and restart the App.
|
||||
|
||||
Configuration of Cosmovisor is done through environment variables, which are
|
||||
documented in: https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor/README.md`,
|
||||
documented in: https://docs.cosmos.network/main/tooling/cosmovisor`,
|
||||
cosmovisor.EnvName, cosmovisor.EnvHome,
|
||||
)
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ func (s *HelpTestSuite) TestGetHelpText() {
|
||||
expectedPieces := []string{
|
||||
"Cosmovisor",
|
||||
cosmovisor.EnvName, cosmovisor.EnvHome,
|
||||
"https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor/README.md",
|
||||
"https://docs.cosmos.network/main/tooling/cosmovisor",
|
||||
}
|
||||
|
||||
actual := GetHelpText()
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"cosmossdk.io/tools/cosmovisor"
|
||||
cverrors "cosmossdk.io/tools/cosmovisor/errors"
|
||||
"cosmossdk.io/x/upgrade/plan"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -77,10 +78,7 @@ func InitializeCosmovisor(logger *zerolog.Logger, args []string) error {
|
||||
logger.Info().Msgf("the %q file already exists", genBinExe)
|
||||
}
|
||||
logger.Info().Msgf("making sure %q is executable", genBinExe)
|
||||
if err = cosmovisor.MarkExecutable(genBinExe); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = cosmovisor.EnsureBinary(genBinExe); err != nil {
|
||||
if err = plan.EnsureBinary(genBinExe); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/tools/cosmovisor"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@ -13,7 +13,11 @@ func TestVersionCommand_Error(t *testing.T) {
|
||||
logger := cosmovisor.NewLogger()
|
||||
|
||||
rootCmd.SetArgs([]string{"version"})
|
||||
_, out := testutil.ApplyMockIO(rootCmd)
|
||||
|
||||
out := bytes.NewBufferString("")
|
||||
rootCmd.SetOut(out)
|
||||
rootCmd.SetErr(out)
|
||||
|
||||
ctx := context.WithValue(context.Background(), cosmovisor.LoggerKey, logger)
|
||||
|
||||
require.Error(t, rootCmd.ExecuteContext(ctx))
|
||||
|
||||
@ -3,8 +3,7 @@ module cosmossdk.io/tools/cosmovisor
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/cosmos/cosmos-sdk v0.47.0-rc2
|
||||
github.com/hashicorp/go-getter v1.6.2
|
||||
cosmossdk.io/x/upgrade v0.0.0-20230202115111-f719cd32adf3
|
||||
github.com/otiai10/copy v1.9.0
|
||||
github.com/rs/zerolog v1.29.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
@ -18,45 +17,54 @@ require (
|
||||
cloud.google.com/go/iam v0.8.0 // indirect
|
||||
cloud.google.com/go/storage v1.27.0 // indirect
|
||||
cosmossdk.io/api v0.2.6 // indirect
|
||||
cosmossdk.io/collections v0.0.0-20230202103518-eb86b68caea0 // indirect
|
||||
cosmossdk.io/core v0.5.1 // indirect
|
||||
cosmossdk.io/depinject v1.0.0-alpha.3 // indirect
|
||||
cosmossdk.io/errors v1.0.0-beta.7 // indirect
|
||||
cosmossdk.io/math v1.0.0-beta.4 // indirect
|
||||
cosmossdk.io/store v0.0.0-20230202103518-eb86b68caea0 // indirect
|
||||
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
|
||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
|
||||
github.com/99designs/keyring v1.2.1 // indirect
|
||||
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
|
||||
github.com/DataDog/zstd v1.4.5 // indirect
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/aws/aws-sdk-go v1.40.45 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cockroachdb/errors v1.9.1 // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||
github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 // indirect
|
||||
github.com/cockroachdb/redact v1.1.3 // indirect
|
||||
github.com/confio/ics23/go v0.9.0 // indirect
|
||||
github.com/cosmos/btcutil v1.0.5 // indirect
|
||||
github.com/cosmos/cosmos-db v0.0.0-20230119180254-161cf3632b7c // indirect
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.1 // indirect
|
||||
github.com/cosmos/cosmos-sdk v0.47.0-rc2 // indirect
|
||||
github.com/cosmos/go-bip39 v1.0.0 // indirect
|
||||
github.com/cosmos/gogogateway v1.2.0 // indirect
|
||||
github.com/cosmos/gogoproto v1.4.4 // indirect
|
||||
github.com/cosmos/gorocksdb v1.2.0 // indirect
|
||||
github.com/cosmos/iavl v0.19.5-rc.1 // indirect
|
||||
github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect
|
||||
github.com/cosmos/iavl v0.20.0-alpha1 // indirect
|
||||
github.com/cosmos/ledger-cosmos-go v0.13.0 // indirect
|
||||
github.com/danieljoos/wincred v1.1.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
|
||||
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/getsentry/sentry-go v0.17.0 // indirect
|
||||
github.com/go-kit/kit v0.12.0 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
@ -65,29 +73,37 @@ require (
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.1 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
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/gtank/merlin v0.1.1 // indirect
|
||||
github.com/gtank/ristretto255 v0.1.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-getter v1.6.2 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect
|
||||
github.com/huandu/skiplist v1.2.0 // indirect
|
||||
github.com/improbable-eng/grpc-web v0.15.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.15.12 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/linxGnu/grocksdb v1.7.10 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||
@ -99,9 +115,11 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
github.com/rs/cors v1.8.2 // indirect
|
||||
github.com/sasha-s/go-deadlock v0.3.1 // indirect
|
||||
github.com/spf13/afero v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
@ -112,17 +130,15 @@ require (
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/tendermint/go-amino v0.16.0 // indirect
|
||||
github.com/tendermint/tendermint v0.37.0-rc2 // indirect
|
||||
github.com/tendermint/tm-db v0.6.7 // indirect
|
||||
github.com/tidwall/btree v1.5.2 // indirect
|
||||
github.com/tidwall/btree v1.6.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.8 // indirect
|
||||
github.com/zondax/hid v0.9.1 // indirect
|
||||
github.com/zondax/ledger-go v0.14.0 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
github.com/zondax/ledger-go v0.14.1 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221019170559-20944726eadf // indirect
|
||||
golang.org/x/crypto v0.5.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230118134722-a68e582fa157 // indirect
|
||||
golang.org/x/net v0.5.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
|
||||
golang.org/x/oauth2 v0.3.0 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/term v0.4.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
@ -135,6 +151,14 @@ require (
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
pgregory.net/rapid v0.5.3 // indirect
|
||||
gotest.tools/v3 v3.4.0 // indirect
|
||||
nhooyr.io/websocket v1.8.6 // indirect
|
||||
pgregory.net/rapid v0.5.5 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
// Using this replace directive as v0.20.0-alpha1 > v0.20.0-alpha.2
|
||||
// This can be deleted when a v0.20.0-alpha3 is tagged or anything lexicographically above than v0.20.0-alpha1
|
||||
replace github.com/cosmos/iavl => github.com/cosmos/iavl v0.20.0-alpha.2
|
||||
|
||||
replace github.com/cosmos/cosmos-sdk => ../..
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,8 @@ import (
|
||||
"github.com/otiai10/copy"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
"cosmossdk.io/x/upgrade/plan"
|
||||
upgradetypes "cosmossdk.io/x/upgrade/types"
|
||||
)
|
||||
|
||||
type Launcher struct {
|
||||
@ -43,7 +44,7 @@ func (l Launcher) Run(args []string, stdout, stderr io.Writer) (bool, error) {
|
||||
return false, fmt.Errorf("error creating symlink to genesis: %w", err)
|
||||
}
|
||||
|
||||
if err := EnsureBinary(bin); err != nil {
|
||||
if err := plan.EnsureBinary(bin); err != nil {
|
||||
return false, fmt.Errorf("current binary is invalid: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/tools/cosmovisor"
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
upgradetypes "cosmossdk.io/x/upgrade/types"
|
||||
)
|
||||
|
||||
type processTestSuite struct {
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
upgradetypes "cosmossdk.io/x/upgrade/types"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
upgradetypes "cosmossdk.io/x/upgrade/types"
|
||||
)
|
||||
|
||||
func TestParseUpgradeInfoFile(t *testing.T) {
|
||||
|
||||
@ -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/tools/cosmovisor/testdata/repo/chain2-zip_bin/autod.zip?checksum=sha256:fd20f3163e5ab2ab430c0c2936de82fcf5f100a8497d7f121b9f34a1a4b96683\"}}"}' >$3
|
||||
echo '{"name":"chain2","height":49,"info":"{\"binaries\":{\"linux/amd64\":\"https://github.com/cosmos/cosmos-sdk/raw/main/tools/cosmovisor/testdata/repo/chain2-zip_bin/autod.zip?checksum=sha256:13767eb0b57bf51a0f43d49f6277d5df97d4dec672dc39822d23a82fb8e70a7b\"}}"}' >$3
|
||||
|
||||
sleep 0.1
|
||||
echo Never should be printed!!!
|
||||
|
||||
@ -6,8 +6,8 @@ echo Args: $@
|
||||
echo 'ERROR: UPGRADE "chain3" NEEDED at height: 936: ref_to_chain3-zip_dir.json module=main'
|
||||
|
||||
# this update info doesn't contain binaries, instead it is a reference for further download instructions.
|
||||
# echo '{"name":"chain3","height":936,"info":"{\"binaries\":{\"linux/amd64\":\"https://github.com/cosmos/cosmos-sdk/raw/main/tools/cosmovisor/testdata/repo/ref_to_chain3-zip_dir.json\"}}"}' > $3
|
||||
echo '{"name":"chain3","height":936,"info":"https://github.com/cosmos/cosmos-sdk/raw/main/tools/cosmovisor/testdata/repo/ref_to_chain3-zip_dir.json"}' >$3
|
||||
# echo '{"name":"chain3","height":936,"info":"{\"binaries\":{\"linux/amd64\":\"https://github.com/cosmos/cosmos-sdk/raw/main/tools/cosmovisor/testdata/repo/ref_to_chain3-zip_dir.json?checksum=sha256:a95075f4dd83bc9f0f556ef73e64ce000f9bf3a6beeb9d4ae32f594b1417ef7a\"}}"}' > $3
|
||||
echo '{"name":"chain3","height":936,"info":"https://github.com/cosmos/cosmos-sdk/raw/main/tools/cosmovisor/testdata/repo/ref_to_chain3-zip_dir.json?checksum=sha256:a95075f4dd83bc9f0f556ef73e64ce000f9bf3a6beeb9d4ae32f594b1417ef7a"}' >$3
|
||||
|
||||
sleep 1
|
||||
echo 'Do not print'
|
||||
|
||||
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo 'exec flag not set'
|
||||
@ -1,30 +1,25 @@
|
||||
package cosmovisor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
"github.com/hashicorp/go-getter"
|
||||
"github.com/otiai10/copy"
|
||||
"cosmossdk.io/x/upgrade/plan"
|
||||
upgradetypes "cosmossdk.io/x/upgrade/types"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// UpgradeBinary 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 UpgradeBinary(logger *zerolog.Logger, cfg *Config, info upgradetypes.Plan) error {
|
||||
func UpgradeBinary(logger *zerolog.Logger, cfg *Config, p upgradetypes.Plan) error {
|
||||
// simplest case is to switch the link
|
||||
err := EnsureBinary(cfg.UpgradeBin(info.Name))
|
||||
err := plan.EnsureBinary(cfg.UpgradeBin(p.Name))
|
||||
if err == nil {
|
||||
// we have the binary - do it
|
||||
return cfg.SetCurrentUpgrade(info)
|
||||
return cfg.SetCurrentUpgrade(p)
|
||||
}
|
||||
|
||||
// if auto-download is disabled, we fail
|
||||
@ -33,7 +28,7 @@ func UpgradeBinary(logger *zerolog.Logger, cfg *Config, info upgradetypes.Plan)
|
||||
}
|
||||
|
||||
// if the dir is there already, don't download either
|
||||
switch fi, err := os.Stat(cfg.UpgradeDir(info.Name)); {
|
||||
switch fi, err := os.Stat(cfg.UpgradeDir(p.Name)); {
|
||||
case fi != nil: // The directory exists, do not overwrite.
|
||||
return errors.New("upgrade dir already exists, won't overwrite")
|
||||
|
||||
@ -44,136 +39,47 @@ func UpgradeBinary(logger *zerolog.Logger, cfg *Config, info upgradetypes.Plan)
|
||||
return fmt.Errorf("unhandled error: %w", err)
|
||||
}
|
||||
|
||||
upgradeInfo, err := plan.ParseInfo(p.Info)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse upgrade info: %w", err)
|
||||
}
|
||||
|
||||
if err := upgradeInfo.ValidateFull(cfg.Name); err != nil {
|
||||
return fmt.Errorf("invalid binaries: %w", err)
|
||||
}
|
||||
|
||||
url, err := GetBinaryURL(upgradeInfo.Binaries)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If not there, then we try to download it... maybe
|
||||
logger.Info().Msg("no upgrade binary found, beginning to download it")
|
||||
if err := DownloadBinary(cfg, info); err != nil {
|
||||
if err := plan.DownloadUpgrade(cfg.UpgradeDir(p.Name), url, cfg.Name); err != nil {
|
||||
return fmt.Errorf("cannot download binary. %w", err)
|
||||
}
|
||||
logger.Info().Msg("downloading binary complete")
|
||||
|
||||
// and then set the binary again
|
||||
if err := EnsureBinary(cfg.UpgradeBin(info.Name)); err != nil {
|
||||
if err := plan.EnsureBinary(cfg.UpgradeBin(p.Name)); err != nil {
|
||||
return fmt.Errorf("downloaded binary doesn't check out: %w", err)
|
||||
}
|
||||
|
||||
return cfg.SetCurrentUpgrade(info)
|
||||
return cfg.SetCurrentUpgrade(p)
|
||||
}
|
||||
|
||||
// DownloadBinary will grab the binary and place it in the proper directory
|
||||
func DownloadBinary(cfg *Config, info upgradetypes.Plan) error {
|
||||
url, err := GetDownloadURL(info)
|
||||
if err != nil {
|
||||
return err
|
||||
func GetBinaryURL(binaries plan.BinaryDownloadURLMap) (string, error) {
|
||||
url, ok := binaries[OSArch()]
|
||||
if !ok {
|
||||
url, ok = binaries["any"]
|
||||
}
|
||||
if !ok {
|
||||
return "", fmt.Errorf("cannot find binary for os/arch: neither %s, nor any", OSArch())
|
||||
}
|
||||
|
||||
// download into the bin dir (works for one file)
|
||||
binPath := cfg.UpgradeBin(info.Name)
|
||||
err = getter.GetFile(binPath, url)
|
||||
|
||||
// if this fails, let's see if it is a zipped directory
|
||||
if err != nil {
|
||||
dirPath := cfg.UpgradeDir(info.Name)
|
||||
err = getter.Get(dirPath, url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = EnsureBinary(binPath)
|
||||
// copy binary to binPath from dirPath if zipped directory don't contain bin directory to wrap the binary
|
||||
if err != nil {
|
||||
err = copy.Copy(filepath.Join(dirPath, cfg.Name), binPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it is successful, let's ensure the binary is executable
|
||||
return MarkExecutable(binPath)
|
||||
}
|
||||
|
||||
// MarkExecutable will try to set the executable bits if not already set
|
||||
// Fails if file doesn't exist or we cannot set those bits
|
||||
func MarkExecutable(path string) error {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stating binary: %w", err)
|
||||
}
|
||||
// end early if world exec already set
|
||||
if info.Mode()&0o001 == 1 {
|
||||
return nil
|
||||
}
|
||||
// now try to set all exec bits
|
||||
newMode := info.Mode().Perm() | 0o111
|
||||
return os.Chmod(path, newMode)
|
||||
}
|
||||
|
||||
// UpgradeConfig is expected format for the info field to allow auto-download
|
||||
type UpgradeConfig struct {
|
||||
Binaries map[string]string `json:"binaries"`
|
||||
}
|
||||
|
||||
// GetDownloadURL will check if there is an arch-dependent binary specified in Info
|
||||
func GetDownloadURL(info upgradetypes.Plan) (string, error) {
|
||||
doc := strings.TrimSpace(info.Info)
|
||||
// if this is a url, then we download that and try to get a new doc with the real info
|
||||
if _, err := url.Parse(doc); err == nil {
|
||||
tmpDir, err := os.MkdirTemp("", "upgrade-manager-reference")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create tempdir for reference file: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
refPath := filepath.Join(tmpDir, "ref")
|
||||
if err := getter.GetFile(refPath, doc); err != nil {
|
||||
return "", fmt.Errorf("downloading reference link %s: %w", doc, err)
|
||||
}
|
||||
|
||||
refBytes, err := os.ReadFile(refPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("reading downloaded reference: %w", err)
|
||||
}
|
||||
// if download worked properly, then we use this new file as the binary map to parse
|
||||
doc = string(refBytes)
|
||||
}
|
||||
|
||||
// check if it is the upgrade config
|
||||
var config UpgradeConfig
|
||||
|
||||
if err := json.Unmarshal([]byte(doc), &config); err == nil {
|
||||
url, ok := config.Binaries[OSArch()]
|
||||
if !ok {
|
||||
url, ok = config.Binaries["any"]
|
||||
}
|
||||
if !ok {
|
||||
return "", fmt.Errorf("cannot find binary for os/arch: neither %s, nor any", OSArch())
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
||||
return "", errors.New("upgrade info doesn't contain binary map")
|
||||
return url, nil
|
||||
}
|
||||
|
||||
func OSArch() string {
|
||||
return fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// EnsureBinary ensures the file exists and is executable, or returns an error
|
||||
func EnsureBinary(path string) error {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot stat dir %s: %w", path, err)
|
||||
}
|
||||
|
||||
if !info.Mode().IsRegular() {
|
||||
return fmt.Errorf("%s is not a regular file", info.Name())
|
||||
}
|
||||
|
||||
// this checks if the world-executable bit is set (we cannot check owner easily)
|
||||
exec := info.Mode().Perm() & 0o001
|
||||
if exec == 0 {
|
||||
return fmt.Errorf("%s is not world executable", info.Name())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -4,9 +4,7 @@
|
||||
package cosmovisor_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -18,7 +16,7 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/tools/cosmovisor"
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
upgradetypes "cosmossdk.io/x/upgrade/types"
|
||||
)
|
||||
|
||||
type upgradeTestSuite struct {
|
||||
@ -39,7 +37,7 @@ func (s *upgradeTestSuite) TestCurrentBin() {
|
||||
s.Require().Equal(cfg.GenesisBin(), currentBin)
|
||||
|
||||
// ensure we cannot set this to an invalid value
|
||||
for _, name := range []string{"missing", "nobin", "noexec"} {
|
||||
for _, name := range []string{"missing", "nobin"} {
|
||||
s.Require().Error(cfg.SetCurrentUpgrade(upgradetypes.Plan{Name: name}), name)
|
||||
|
||||
currentBin, err := cfg.CurrentBin()
|
||||
@ -103,7 +101,7 @@ func (s *upgradeTestSuite) TestUpgradeBinaryNoDownloadUrl() {
|
||||
s.Require().Equal(cfg.GenesisBin(), currentBin)
|
||||
|
||||
// do upgrade ignores bad files
|
||||
for _, name := range []string{"missing", "nobin", "noexec"} {
|
||||
for _, name := range []string{"missing", "nobin"} {
|
||||
info := upgradetypes.Plan{Name: name}
|
||||
err = cosmovisor.UpgradeBinary(logger, cfg, info)
|
||||
s.Require().Error(err, name)
|
||||
@ -127,97 +125,14 @@ func (s *upgradeTestSuite) TestUpgradeBinaryNoDownloadUrl() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *upgradeTestSuite) TestOsArch() {
|
||||
// all download tests will fail if we are not on linux...
|
||||
s.Require().Equal("linux/amd64", cosmovisor.OSArch())
|
||||
}
|
||||
func (s *upgradeTestSuite) TestUpgradeBinary() {
|
||||
logger := cosmovisor.NewLogger()
|
||||
|
||||
func (s *upgradeTestSuite) TestGetDownloadURL() {
|
||||
// all download tests will fail if we are not on linux...
|
||||
ref, err := filepath.Abs(filepath.FromSlash("./testdata/repo/ref_to_chain3-zip_dir.json"))
|
||||
s.Require().NoError(err)
|
||||
badref, err := filepath.Abs(filepath.FromSlash("./testdata/repo/chain2-zip_bin/autod.zip")) // "./testdata/repo/zip_binary/autod.zip"))
|
||||
s.Require().NoError(err)
|
||||
|
||||
cases := map[string]struct {
|
||||
info string
|
||||
url string
|
||||
err interface{}
|
||||
|
||||
// If err == nil, the test must not report an error.
|
||||
// If err is a string, the test must report an error whose string has err
|
||||
// as a substring.
|
||||
// If err is a func(suite.Suite, error), it is called to check the error
|
||||
// value.
|
||||
}{
|
||||
"missing": {
|
||||
err: "downloading reference link : invalid source string:",
|
||||
},
|
||||
"follow reference": {
|
||||
info: ref,
|
||||
url: "https://github.com/cosmos/cosmos-sdk/raw/main/tools/cosmovisor/testdata/repo/chain3-zip_dir/autod.zip?checksum=sha256:8951f52a0aea8617de0ae459a20daf704c29d259c425e60d520e363df0f166b4",
|
||||
},
|
||||
"malformated reference target": {
|
||||
info: badref,
|
||||
err: "upgrade info doesn't contain binary map",
|
||||
},
|
||||
"missing link": {
|
||||
info: "https://no.such.domain/exists.txt",
|
||||
err: func(s suite.Suite, err error) {
|
||||
var dns *net.DNSError
|
||||
s.Require().True(errors.As(err, &dns), "result is not a DNSError")
|
||||
s.Require().Equal("no.such.domain", dns.Name)
|
||||
s.Require().Equal(true, dns.IsNotFound)
|
||||
},
|
||||
},
|
||||
"proper binary": {
|
||||
info: `{"binaries": {"linux/amd64": "https://foo.bar/", "windows/amd64": "https://something.else"}}`,
|
||||
url: "https://foo.bar/",
|
||||
},
|
||||
"any architecture not used": {
|
||||
info: `{"binaries": {"linux/amd64": "https://foo.bar/", "*": "https://something.else"}}`,
|
||||
url: "https://foo.bar/",
|
||||
},
|
||||
"any architecture used": {
|
||||
info: `{"binaries": {"linux/arm": "https://foo.bar/arm-only", "any": "https://foo.bar/portable"}}`,
|
||||
url: "https://foo.bar/portable",
|
||||
},
|
||||
"missing binary": {
|
||||
info: `{"binaries": {"linux/arm": "https://foo.bar/"}}`,
|
||||
err: "cannot find binary for",
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
s.Run(name, func() {
|
||||
url, err := cosmovisor.GetDownloadURL(upgradetypes.Plan{Info: tc.info})
|
||||
switch e := tc.err.(type) {
|
||||
case nil:
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(tc.url, url)
|
||||
|
||||
case string:
|
||||
s.Require().Error(err)
|
||||
s.Require().Contains(err.Error(), tc.err)
|
||||
|
||||
case func(suite.Suite, error):
|
||||
e(s.Suite, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *upgradeTestSuite) TestDownloadBinary() {
|
||||
cases := map[string]struct {
|
||||
url string
|
||||
canDownload bool
|
||||
validBinary bool
|
||||
}{
|
||||
"get raw binary": {
|
||||
url: "./testdata/repo/raw_binary/autod",
|
||||
canDownload: true,
|
||||
validBinary: true,
|
||||
},
|
||||
"get raw binary with checksum": {
|
||||
// sha256sum ./testdata/repo/raw_binary/autod
|
||||
url: "./testdata/repo/raw_binary/autod?checksum=sha256:e6bc7851600a2a9917f7bf88eb7bdee1ec162c671101485690b4deb089077b0d",
|
||||
@ -228,11 +143,6 @@ func (s *upgradeTestSuite) TestDownloadBinary() {
|
||||
url: "./testdata/repo/raw_binary/autod?checksum=sha256:73e2bd6cbb99261733caf137015d5cc58e3f96248d8b01da68be8564989dd906",
|
||||
canDownload: false,
|
||||
},
|
||||
"get zipped directory": {
|
||||
url: "./testdata/repo/chain3-zip_dir/autod.zip",
|
||||
canDownload: true,
|
||||
validBinary: true,
|
||||
},
|
||||
"get zipped directory with valid checksum": {
|
||||
// sha256sum ./testdata/repo/chain3-zip_dir/autod.zip
|
||||
url: "./testdata/repo/chain3-zip_dir/autod.zip?checksum=sha256:8951f52a0aea8617de0ae459a20daf704c29d259c425e60d520e363df0f166b4",
|
||||
@ -244,9 +154,14 @@ func (s *upgradeTestSuite) TestDownloadBinary() {
|
||||
canDownload: false,
|
||||
},
|
||||
"invalid url": {
|
||||
url: "./testdata/repo/bad_dir/autod",
|
||||
url: "./testdata/repo/bad_dir/autod?checksum=sha256:73e2bd6cbb99261733caf137015d5cc58e3f96248d8b01da68be8564989dd906",
|
||||
canDownload: false,
|
||||
},
|
||||
"valid remote": {
|
||||
url: "https://github.com/cosmos/cosmos-sdk/raw/main/tools/cosmovisor/testdata/repo/chain3-zip_dir/autod.zip?checksum=sha256:8951f52a0aea8617de0ae459a20daf704c29d259c425e60d520e363df0f166b4",
|
||||
canDownload: true,
|
||||
validBinary: true,
|
||||
},
|
||||
}
|
||||
|
||||
for label, tc := range cases {
|
||||
@ -267,27 +182,26 @@ func (s *upgradeTestSuite) TestDownloadBinary() {
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
const upgrade = "amazonas"
|
||||
info := upgradetypes.Plan{
|
||||
Name: upgrade,
|
||||
plan := upgradetypes.Plan{
|
||||
Name: "amazonas",
|
||||
Info: fmt.Sprintf(`{"binaries":{"%s": "%s"}}`, cosmovisor.OSArch(), url),
|
||||
}
|
||||
|
||||
err = cosmovisor.DownloadBinary(cfg, info)
|
||||
err = cosmovisor.UpgradeBinary(logger, cfg, plan)
|
||||
if !tc.canDownload {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
err = cosmovisor.EnsureBinary(cfg.UpgradeBin(upgrade))
|
||||
if tc.validBinary {
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *upgradeTestSuite) TestOsArch() {
|
||||
// all download tests will fail if we are not on linux...
|
||||
s.Require().Equal("linux/amd64", cosmovisor.OSArch())
|
||||
}
|
||||
|
||||
// copyTestData will make a tempdir and then
|
||||
// "cp -r" a subdirectory under testdata there
|
||||
// returns the directory (which can now be used as Config.Home) and modified safely
|
||||
|
||||
@ -111,7 +111,7 @@ func NewCmdSubmitUpgradeProposal() *cobra.Command {
|
||||
|
||||
cmd.Flags().Int64(FlagUpgradeHeight, 0, "The height at which the upgrade must happen")
|
||||
cmd.Flags().String(FlagUpgradeInfo, "", "Info for the upgrade plan such as new version download urls, etc.")
|
||||
cmd.Flags().Bool(FlagNoValidate, false, "Skip validation of the upgrade info")
|
||||
cmd.Flags().Bool(FlagNoValidate, false, "Skip validation of the upgrade info (dangerous!)")
|
||||
cmd.Flags().String(FlagDaemonName, getDefaultDaemonName(), "The name of the executable being upgraded (for upgrade-info validation). Default is the DAEMON_NAME env var if set, or else this executable")
|
||||
cmd.Flags().String(FlagAuthority, "", "The address of the upgrade module authority (defaults to gov)")
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user