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

Config file lock #987

Merged
merged 1 commit into from
Sep 15, 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
30 changes: 15 additions & 15 deletions _test/relayer_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ func chainTest(t *testing.T, tcs []testChain) {
require.NoError(t, eg.Wait())

t.Log("Creating clients")
_, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
_, _, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
require.NoError(t, err)
testClientPair(ctx, t, src, dst)

timeout, err := src.GetTimeout()
require.NoError(t, err)

t.Log("Creating connections")
_, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
_, _, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
require.NoError(t, err)
testConnectionPair(ctx, t, src, dst)

Expand Down Expand Up @@ -165,14 +165,14 @@ func TestGaiaReuseIdentifiers(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

_, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
_, _, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
require.NoError(t, err)
testClientPair(ctx, t, src, dst)

timeout, err := src.GetTimeout()
require.NoError(t, err)

_, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
_, _, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
require.NoError(t, err)
testConnectionPair(ctx, t, src, dst)

Expand All @@ -195,11 +195,11 @@ func TestGaiaReuseIdentifiers(t *testing.T) {
dst.PathEnd.ClientID = ""
dst.PathEnd.ConnectionID = ""

_, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
_, _, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
require.NoError(t, err)
testClientPair(ctx, t, src, dst)

_, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
_, _, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
require.NoError(t, err)
testConnectionPair(ctx, t, src, dst)

Expand All @@ -217,7 +217,7 @@ func TestGaiaReuseIdentifiers(t *testing.T) {
src.PathEnd.ClientID = ""
dst.PathEnd.ClientID = ""

_, err = src.CreateClients(ctx, dst, true, true, true, 0, "")
_, _, err = src.CreateClients(ctx, dst, true, true, true, 0, "")
require.NoError(t, err)
testClientPair(ctx, t, src, dst)

Expand Down Expand Up @@ -246,14 +246,14 @@ func TestGaiaMisbehaviourMonitoring(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

_, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
_, _, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
require.NoError(t, err)
testClientPair(ctx, t, src, dst)

timeout, err := src.GetTimeout()
require.NoError(t, err)

_, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
_, _, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
require.NoError(t, err)
testConnectionPair(ctx, t, src, dst)

Expand Down Expand Up @@ -386,15 +386,15 @@ func TestRelayAllChannelsOnConnection(t *testing.T) {
require.NoError(t, eg.Wait())

t.Log("Creating clients")
_, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
_, _, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
require.NoError(t, err)
testClientPair(ctx, t, src, dst)

timeout, err := src.GetTimeout()
require.NoError(t, err)

t.Log("Creating connections")
_, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
_, _, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
require.NoError(t, err)
testConnectionPair(ctx, t, src, dst)

Expand Down Expand Up @@ -583,14 +583,14 @@ func TestUnorderedChannelBlockHeightTimeout(t *testing.T) {
require.NoError(t, eg.Wait())

// create path
_, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
_, _, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
require.NoError(t, err)
testClientPair(ctx, t, src, dst)

timeout, err := src.GetTimeout()
require.NoError(t, err)

_, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
_, _, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
require.NoError(t, err)
testConnectionPair(ctx, t, src, dst)

Expand Down Expand Up @@ -681,14 +681,14 @@ func TestUnorderedChannelTimestampTimeout(t *testing.T) {
require.NoError(t, eg.Wait())

// create path
_, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
_, _, err = src.CreateClients(ctx, dst, true, true, false, 0, "")
require.NoError(t, err)
testClientPair(ctx, t, src, dst)

timeout, err := src.GetTimeout()
require.NoError(t, err)

_, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
_, _, err = src.CreateOpenConnections(ctx, dst, 3, timeout, "", 0, "")
require.NoError(t, err)
testConnectionPair(ctx, t, src, dst)

Expand Down
70 changes: 70 additions & 0 deletions cmd/appstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ package cmd
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path"
"time"

"github.com/cosmos/relayer/v2/relayer"
"github.com/juju/fslock"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -159,3 +163,69 @@ func (a *appState) OverwriteConfig(cfg *Config) error {
a.Config = cfg
return nil
}

// OverwriteConfigOnTheFly overwrites the config file concurrently,
// locking to read, modify, then write the config.
func (a *appState) OverwriteConfigOnTheFly(
cmd *cobra.Command,
pathName string,
clientSrc, clientDst string,
connectionSrc, connectionDst string,
) error {
if pathName == "" {
return errors.New("empty path name not allowed")
}

// use lock file to guard concurrent access to config.yaml
lockFilePath := path.Join(a.HomePath, "config", "config.lock")
lock := fslock.New(lockFilePath)
err := lock.LockWithTimeout(10 * time.Second)
if err != nil {
return fmt.Errorf("failed to acquire config lock: %w", err)
}
defer func() {
if err := lock.Unlock(); err != nil {
a.Log.Error("error unlocking config file lock, please manually delete",
zap.String("filepath", lockFilePath),
)
}
}()

// load config from file and validate it. don't want to miss
// any changes that may have been made while unlocked.
if err := initConfig(cmd, a); err != nil {
return fmt.Errorf("failed to initialize config from file: %w", err)
}

path, ok := a.Config.Paths[pathName]
if !ok {
return fmt.Errorf("config does not exist for that path: %s", pathName)
}
if clientSrc != "" {
path.Src.ClientID = clientSrc
}
if clientDst != "" {
path.Dst.ClientID = clientDst
}
if connectionSrc != "" {
path.Src.ConnectionID = connectionSrc
}
if connectionDst != "" {
path.Dst.ConnectionID = connectionDst
}

// marshal the new config
out, err := yaml.Marshal(a.Config.Wrapped())
if err != nil {
return err
}

cfgPath := a.Viper.ConfigFileUsed()

// Overwrite the config file.
if err := os.WriteFile(cfgPath, out, 0600); err != nil {
return fmt.Errorf("failed to write config file at %s: %w", cfgPath, err)
}

return nil
}
11 changes: 7 additions & 4 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -538,12 +538,15 @@ func validateConfig(c *Config) error {

// initConfig reads config file into a.Config if file is present.
func initConfig(cmd *cobra.Command, a *appState) error {
home, err := cmd.PersistentFlags().GetString(flagHome)
if err != nil {
return err
if a.HomePath == "" {
var err error
a.HomePath, err = cmd.PersistentFlags().GetString(flagHome)
if err != nil {
return err
}
}

cfgPath := path.Join(home, "config", "config.yaml")
cfgPath := path.Join(a.HomePath, "config", "config.yaml")
if _, err := os.Stat(cfgPath); err != nil {
// don't return error if file doesn't exist
return nil
Expand Down
46 changes: 27 additions & 19 deletions cmd/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ func createClientsCmd(a *appState) *cobra.Command {
return err
}

c, src, dst, err := a.Config.ChainsFromPath(args[0])
path := args[0]

c, src, dst, err := a.Config.ChainsFromPath(path)
if err != nil {
return err
}
Expand All @@ -90,12 +92,12 @@ func createClientsCmd(a *appState) *cobra.Command {
return fmt.Errorf("key %s not found on dst chain %s", c[dst].ChainProvider.Key(), c[dst].ChainID())
}

modified, err := c[src].CreateClients(cmd.Context(), c[dst], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, a.Config.memo(cmd))
clientSrc, clientDst, err := c[src].CreateClients(cmd.Context(), c[dst], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, a.Config.memo(cmd))
if err != nil {
return err
}
if modified {
if err := a.OverwriteConfig(a.Config); err != nil {
if clientSrc != "" || clientDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, path, clientSrc, clientDst, "", ""); err != nil {
return err
}
}
Expand Down Expand Up @@ -201,12 +203,18 @@ func createClientCmd(a *appState) *cobra.Command {
return err
}

modified, err := relayer.CreateClient(cmd.Context(), src, dst, srcUpdateHeader, dstUpdateHeader, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, a.Config.memo(cmd))
clientID, err := relayer.CreateClient(cmd.Context(), src, dst, srcUpdateHeader, dstUpdateHeader, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, a.Config.memo(cmd))
if err != nil {
return err
}
if modified {
if err = a.OverwriteConfig(a.Config); err != nil {
var clientSrc, clientDst string
if path.Src.ChainID == src.ChainID() {
clientSrc = clientID
} else {
clientDst = clientID
}
if clientID != "" {
if err = a.OverwriteConfigOnTheFly(cmd, pathName, clientSrc, clientDst, "", ""); err != nil {
return err
}
}
Expand Down Expand Up @@ -361,22 +369,22 @@ $ %s tx conn demo-path --timeout 5s`,
}

// ensure that the clients exist
modified, err := c[src].CreateClients(cmd.Context(), c[dst], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, memo)
clientSrc, clientDst, err := c[src].CreateClients(cmd.Context(), c[dst], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, memo)
if err != nil {
return err
}
if modified {
if err := a.OverwriteConfig(a.Config); err != nil {
if clientSrc != "" || clientDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, pathName, clientSrc, clientDst, "", ""); err != nil {
return err
}
}

modified, err = c[src].CreateOpenConnections(cmd.Context(), c[dst], retries, to, memo, initialBlockHistory, pathName)
connectionSrc, connectionDst, err := c[src].CreateOpenConnections(cmd.Context(), c[dst], retries, to, memo, initialBlockHistory, pathName)
if err != nil {
return err
}
if modified {
if err := a.OverwriteConfig(a.Config); err != nil {
if connectionSrc != "" || connectionDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, pathName, "", "", connectionSrc, connectionDst); err != nil {
return err
}
}
Expand Down Expand Up @@ -632,23 +640,23 @@ $ %s tx connect demo-path --src-port transfer --dst-port transfer --order unorde
}

// create clients if they aren't already created
modified, err := c[src].CreateClients(cmd.Context(), c[dst], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, memo)
clientSrc, clientDst, err := c[src].CreateClients(cmd.Context(), c[dst], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, memo)
if err != nil {
return fmt.Errorf("error creating clients: %w", err)
}
if modified {
if err := a.OverwriteConfig(a.Config); err != nil {
if clientSrc != "" || clientDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, pathName, clientSrc, clientDst, "", ""); err != nil {
return err
}
}

// create connection if it isn't already created
modified, err = c[src].CreateOpenConnections(cmd.Context(), c[dst], retries, to, memo, initialBlockHistory, pathName)
connectionSrc, connectionDst, err := c[src].CreateOpenConnections(cmd.Context(), c[dst], retries, to, memo, initialBlockHistory, pathName)
if err != nil {
return fmt.Errorf("error creating connections: %w", err)
}
if modified {
if err := a.OverwriteConfig(a.Config); err != nil {
if connectionSrc != "" || connectionDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, pathName, "", "", connectionSrc, connectionDst); err != nil {
return err
}
}
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/google/go-cmp v0.5.8
github.com/google/go-github/v43 v43.0.0
github.com/jsternberg/zap-logfmt v1.2.0
github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b
github.com/ory/dockertest/v3 v3.9.1
github.com/prometheus/client_golang v1.12.2
github.com/spf13/cobra v1.5.0
Expand All @@ -34,7 +35,9 @@ require (
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/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/Workiva/go-datastructures v1.0.53 // indirect
github.com/armon/go-metrics v0.4.0 // indirect
Expand Down Expand Up @@ -174,7 +177,6 @@ require (
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 // indirect
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
nhooyr.io/websocket v1.8.6 // indirect
Expand Down
Loading