diff --git a/README.md b/README.md index 306a97d..6921c0e 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,6 @@ All options can be passed either as command-line flags or environment variables: | `--cluster-key KEY` | WESHER_CLUSTER_KEY | shared key for cluster membership; must be 32 bytes base64 encoded; will be generated if not provided | autogenerated/loaded | | `--join HOST,...` | WESHER_JOIN | comma separated list of hostnames or IP addresses to existing cluster members; if not provided, will attempt resuming any known state or otherwise wait for further members | | | `--init` | WESHER_INIT | whether to explicitly (re)initialize the cluster; any known state from previous runs will be forgotten | `false` | -| `--cluster-name` | WESHER_CLUSTER_NAME | Identifier for the wesher cluster; can be used to peer with multiple clusters | `default` | | `--bind-addr ADDR` | WESHER_BIND_ADDR | IP address to bind to for cluster membership (cannot be used with --bind-iface) | autodetected | | `--bind-iface IFACE` | WESHER_BIND_IFACE | Interface to bind to for cluster membership (cannot be used with --bind-addr)| | | `--cluster-port PORT` | WESHER_CLUSTER_PORT | port used for membership gossip traffic (both TCP and UDP); must be the same across cluster | `7946` | @@ -147,6 +146,16 @@ All options can be passed either as command-line flags or environment variables: | `--no-etc-hosts` | WESHER_NO_ETC_HOSTS | whether to skip writing hosts entries for each node in mesh | `false` | | `--log-level LEVEL` | WESHER_LOG_LEVEL | set the verbosity (one of debug/info/warn/error) | `warn` | +## Running multiple clusters + +Wesher supports having a node be a member of multiple clusters. The following settings must be explicitely set to non-conflicting values: +- `--interface`, so that wireguard does not mix up traffic, the interface name is also used for naming the state file +- `--cluster-port` or `--bind-addr` or `--bind-iface`, so that wesher can properly bind to its port +- `--wireguard-port`, so that wireguard can properly bind to its port + +One should also use different overlay networks. Even though using the same network on different devices will work in some cases, it is not the intended use. + +Finally, one should use different cluster keys for different clusters, as a security best practice. ## Security considerations diff --git a/cluster/state.go b/cluster/state.go index 66b54b3..7a7117b 100644 --- a/cluster/state.go +++ b/cluster/state.go @@ -17,10 +17,12 @@ type state struct { Nodes []common.Node } -var defaultStatePath = "/var/lib/wesher/%s.json" +var statePathTemplate = "/var/lib/wesher/%s.json" + +const deprecatedStatePath = "/var/lib/wesher/state.json" func (s *state) save(clusterName string) error { - statePath := fmt.Sprintf(defaultStatePath, clusterName) + statePath := fmt.Sprintf(statePathTemplate, clusterName) if err := os.MkdirAll(path.Dir(statePath), 0700); err != nil { return err } @@ -34,13 +36,21 @@ func (s *state) save(clusterName string) error { } func loadState(cs *state, clusterName string) { - statePath := fmt.Sprintf(defaultStatePath, clusterName) + statePath := fmt.Sprintf(statePathTemplate, clusterName) content, err := ioutil.ReadFile(statePath) if err != nil { - if !os.IsNotExist(err) { - logrus.Warnf("could not open state in %s: %s", statePath, err) + // try the deprecated pre 0.3 state path, it will later + // be saved to the proper path + if os.IsNotExist(err) { + content, err = ioutil.ReadFile(deprecatedStatePath) + } + + if err != nil { + if !os.IsNotExist(err) { + logrus.Warnf("could not open state in %s: %s", statePath, err) + } + return } - return } // avoid partially unmarshalled content by using a temp var diff --git a/cluster/state_test.go b/cluster/state_test.go index af422ce..38be58a 100644 --- a/cluster/state_test.go +++ b/cluster/state_test.go @@ -9,7 +9,7 @@ import ( ) func Test_state_save_soad(t *testing.T) { - defaultStatePath = "/tmp/%s.json" + statePathTemplate = "/tmp/%s.json" key := "abcdefghijklmnopqrstuvwxyzABCDEF" node := common.Node{ Name: "node", diff --git a/config.go b/config.go index 48f4713..2f4ea4f 100644 --- a/config.go +++ b/config.go @@ -14,7 +14,6 @@ type config struct { ClusterKey []byte `id:"cluster-key" desc:"shared key for cluster membership; must be 32 bytes base64 encoded; will be generated if not provided"` Join []string `desc:"comma separated list of hostnames or IP addresses to existing cluster members; if not provided, will attempt resuming any known state or otherwise wait for further members."` Init bool `desc:"whether to explicitly (re)initialize the cluster; any known state from previous runs will be forgotten"` - ClusterName string `id:"cluster-name" desc:"identifier for the wesher cluster; can be used to peer with multiple clusters" default:"default"` BindAddr string `id:"bind-addr" desc:"IP address to bind to for cluster membership traffic (cannot be used with --bind-iface)"` BindIface string `id:"bind-iface" desc:"Interface to bind to for cluster membership traffic (cannot be used with --bind-addr)"` ClusterPort int `id:"cluster-port" desc:"port used for membership gossip traffic (both TCP and UDP); must be the same across cluster" default:"7946"` diff --git a/main.go b/main.go index e7b1ba1..570eb97 100644 --- a/main.go +++ b/main.go @@ -35,7 +35,7 @@ func main() { logrus.SetLevel(logLevel) // Create the wireguard and cluster configuration - cluster, err := cluster.New(config.ClusterName, config.Init, config.ClusterKey, config.BindAddr, config.ClusterPort, config.UseIPAsName) + cluster, err := cluster.New(config.Interface, config.Init, config.ClusterKey, config.BindAddr, config.ClusterPort, config.UseIPAsName) if err != nil { logrus.WithError(err).Fatal("could not create cluster") } @@ -46,7 +46,7 @@ func main() { // Prepare the /etc/hosts writer hostsFile := &etchosts.EtcHosts{ - Banner: "# ! managed automatically by wesher " + config.ClusterName, + Banner: "# ! managed automatically by wesher interface " + config.Interface, Logger: logrus.StandardLogger(), } diff --git a/tests/e2e.sh b/tests/e2e.sh index 1165b31..e133719 100755 --- a/tests/e2e.sh +++ b/tests/e2e.sh @@ -101,8 +101,8 @@ test_cluster_simultaneous_start() { } test_multiple_clusters_restart() { - cluster1='--cluster-port 7946 --wireguard-port 51820 --cluster-name cluster1 --interface wgoverlay --overlay-net 10.10.0.0/16' - cluster2='--cluster-port 7947 --wireguard-port 51821 --cluster-name cluster2 --interface wgoverlay2 --overlay-net 10.11.0.0/16' + cluster1='--cluster-port 7946 --wireguard-port 51820 --interface wgoverlay --overlay-net 10.10.0.0/16' + cluster2='--cluster-port 7947 --wireguard-port 51821 --interface wgoverlay2 --overlay-net 10.11.0.0/16' setup_wireguard='wireguard-go wgoverlay2 2>/dev/null >/dev/null' join_cluster2="nohup /app/wesher --cluster-key 'ILICZ3yBMCGAWNIq5Pn0bewBVimW3Q2yRVJ/Be+b1Uc=' --join test2-orig $cluster2 2>/dev/null &"