Implement node function as type functions

This means nodeMeta can be private again, and also makes it
easier to pass a Node object to the cluster for local meta,
instead of a generic byte[] function.

For later updating, that node is passed using Update() instead
of New().
This commit is contained in:
kaiyou 2020-05-07 11:36:46 +02:00 committed by Leo Antunes
parent dadfbee083
commit 46da51b7aa
3 changed files with 41 additions and 36 deletions

View File

@ -28,14 +28,14 @@ type State struct {
type Cluster struct { type Cluster struct {
LocalName string // used to avoid LocalNode(); should not change LocalName string // used to avoid LocalNode(); should not change
ml *memberlist.Memberlist ml *memberlist.Memberlist
getMeta func(int) []byte localNode common.Node
state *State state *State
events chan memberlist.NodeEvent events chan memberlist.NodeEvent
} }
const statePath = "/var/lib/wesher/state.json" const statePath = "/var/lib/wesher/state.json"
func New(init bool, clusterKey []byte, bindAddr string, bindPort int, useIPAsName bool, getMeta func(int) []byte) (*Cluster, error) { func New(init bool, clusterKey []byte, bindAddr string, bindPort int, useIPAsName bool) (*Cluster, error) {
state := &State{} state := &State{}
if !init { if !init {
loadState(state) loadState(state)
@ -64,7 +64,6 @@ func New(init bool, clusterKey []byte, bindAddr string, bindPort int, useIPAsNam
cluster := Cluster{ cluster := Cluster{
LocalName: ml.LocalNode().Name, LocalName: ml.LocalNode().Name,
ml: ml, ml: ml,
getMeta: getMeta,
// The big channel buffer is a work-around for https://github.com/hashicorp/memberlist/issues/23 // The big channel buffer is a work-around for https://github.com/hashicorp/memberlist/issues/23
// More than this many simultaneous events will deadlock cluster.members() // More than this many simultaneous events will deadlock cluster.members()
events: make(chan memberlist.NodeEvent, 100), events: make(chan memberlist.NodeEvent, 100),
@ -82,7 +81,12 @@ func (c *Cluster) NotifyConflict(node, other *memberlist.Node) {
} }
func (c *Cluster) NodeMeta(limit int) []byte { func (c *Cluster) NodeMeta(limit int) []byte {
return c.getMeta(limit) encoded, err := c.localNode.Encode(limit)
if err != nil {
logrus.Errorf("failed to encode local node: %s", err)
return nil
}
return encoded
} }
// none of these are used // none of these are used
@ -112,7 +116,8 @@ func (c *Cluster) Leave() {
c.ml.Shutdown() //nolint: errcheck c.ml.Shutdown() //nolint: errcheck
} }
func (c *Cluster) Update() { func (c *Cluster) Update(localNode common.Node) {
c.localNode = localNode
c.ml.UpdateNode(1 * time.Second) // we currently do not update after creation c.ml.UpdateNode(1 * time.Second) // we currently do not update after creation
} }

View File

@ -6,11 +6,10 @@ import (
"net" "net"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
// NodeMeta holds metadata sent over the cluster // nodeMeta holds metadata sent over the cluster
type NodeMeta struct { type nodeMeta struct {
OverlayAddr net.IPNet OverlayAddr net.IPNet
PubKey string PubKey string
} }
@ -20,32 +19,40 @@ type Node struct {
Name string Name string
Addr net.IP Addr net.IP
Meta []byte Meta []byte
NodeMeta nodeMeta
} }
func (n *Node) String() string { func (n *Node) String() string {
return n.Addr.String() return n.Addr.String()
} }
func EncodeNodeMeta(nm NodeMeta, limit int) []byte { func MakeLocalNode(overlayAddr net.IPNet, pubKey string) Node {
buf := &bytes.Buffer{} return Node{
if err := gob.NewEncoder(buf).Encode(nm); err != nil { nodeMeta: nodeMeta{
logrus.Errorf("could not encode local state: %s", err) OverlayAddr: overlayAddr,
return nil PubKey: pubKey,
},
} }
if buf.Len() > limit {
logrus.Errorf("could not fit node metadata into %d bytes", limit)
return nil
}
return buf.Bytes()
} }
func DecodeNodeMeta(b []byte) (NodeMeta, error) { func (n *Node) Encode(limit int) ([]byte, error) {
buf := &bytes.Buffer{}
if err := gob.NewEncoder(buf).Encode(n.nodeMeta); err != nil {
return nil, errors.Wrap(err, "could not encode local state")
}
if buf.Len() > limit {
return nil, errors.Errorf("could not fit node metadata into %d bytes", limit)
}
return buf.Bytes(), nil
}
func (n *Node) Decode() error {
// TODO: we blindly trust the info we get from the peers; We should be more defensive to limit the damage a leaked // TODO: we blindly trust the info we get from the peers; We should be more defensive to limit the damage a leaked
// PSK can cause. // PSK can cause.
nm := NodeMeta{} nm := nodeMeta{}
if err := gob.NewDecoder(bytes.NewReader(b)).Decode(&nm); err != nil { if err := gob.NewDecoder(bytes.NewReader(n.Meta)).Decode(&nm); err != nil {
return nm, errors.Wrap(err, "could not decode node meta") return errors.Wrap(err, "could not decode node meta")
} }
return nm, nil n.nodeMeta = nm
return nil
} }

17
main.go
View File

@ -38,19 +38,14 @@ func main() {
logrus.WithError(err).Fatal("could not instantiate wireguard controller") logrus.WithError(err).Fatal("could not instantiate wireguard controller")
} }
getMeta := func(limit int) []byte { cluster, err := cluster.New(config.Init, config.ClusterKey, config.BindAddr, config.ClusterPort, config.UseIPAsName)
return common.EncodeNodeMeta(common.NodeMeta{
OverlayAddr: wg.OverlayAddr,
PubKey: wg.PubKey.String(),
}, limit)
}
cluster, err := cluster.New(config.Init, config.ClusterKey, config.BindAddr, config.ClusterPort, config.UseIPAsName, getMeta)
if err != nil { if err != nil {
logrus.WithError(err).Fatal("could not create cluster") logrus.WithError(err).Fatal("could not create cluster")
} }
wg.AssignOverlayAddr((*net.IPNet)(config.OverlayNet), cluster.LocalName) wg.AssignOverlayAddr((*net.IPNet)(config.OverlayNet), cluster.LocalName)
cluster.Update() localNode := common.MakeLocalNode(wg.OverlayAddr, wg.PubKey.String())
cluster.Update(localNode)
nodec := cluster.Members() // avoid deadlocks by starting before join nodec := cluster.Members() // avoid deadlocks by starting before join
if err := backoff.RetryNotify( if err := backoff.RetryNotify(
@ -72,12 +67,10 @@ func main() {
logrus.Info("cluster members:\n") logrus.Info("cluster members:\n")
nodes := make([]common.Node, 0, len(rawNodes)) nodes := make([]common.Node, 0, len(rawNodes))
for _, node := range rawNodes { for _, node := range rawNodes {
meta, err := common.DecodeNodeMeta(node.Meta) if err := node.Decode(); err != nil {
if err != nil {
logrus.Warnf("\t addr: %s, could not decode metadata", node.Addr) logrus.Warnf("\t addr: %s, could not decode metadata", node.Addr)
continue continue
} }
node.NodeMeta = meta
nodes = append(nodes, node) nodes = append(nodes, node)
logrus.Infof("\taddr: %s, overlay: %s, pubkey: %s", node.Addr, node.OverlayAddr, node.PubKey) logrus.Infof("\taddr: %s, overlay: %s, pubkey: %s", node.Addr, node.OverlayAddr, node.PubKey)
} }