diff --git a/cli/server/command.go b/cli/server/command.go index c22bc8cb..cdc60949 100644 --- a/cli/server/command.go +++ b/cli/server/command.go @@ -11,6 +11,8 @@ import ( "github.com/andydunstall/pico/pkg/log" "github.com/andydunstall/pico/server" "github.com/andydunstall/pico/server/config" + "github.com/andydunstall/pico/server/gossip" + "github.com/andydunstall/pico/server/netmap" "github.com/prometheus/client_golang/prometheus" "github.com/spf13/cobra" "go.uber.org/zap" @@ -183,6 +185,11 @@ func run(conf *config.Config, logger *log.Logger) { logger, ) + netmap := netmap.NewNetworkMap() + // TODO(andydunstall): Should wait for gossip to join and sync before + // the server becomes ready. + gossip := gossip.NewGossip(netmap, logger) + ctx, cancel := signal.NotifyContext( context.Background(), syscall.SIGINT, syscall.SIGTERM, ) @@ -211,6 +218,12 @@ func run(conf *config.Config, logger *log.Logger) { } return nil }) + g.Go(func() error { + if err := gossip.Run(ctx); err != nil { + return fmt.Errorf("gossip: %w", err) + } + return nil + }) if err := g.Wait(); err != nil { logger.Error("failed to run server", zap.Error(err)) diff --git a/server/gossip/gossip.go b/server/gossip/gossip.go new file mode 100644 index 00000000..8c0c434b --- /dev/null +++ b/server/gossip/gossip.go @@ -0,0 +1,29 @@ +package gossip + +import ( + "context" + + "github.com/andydunstall/pico/pkg/log" + "github.com/andydunstall/pico/server/netmap" +) + +// Gossip is responsible for maintaining the nodes local NetworkMap and +// propagating the state of the local node to the rest of the cluster. +type Gossip struct { + netmap *netmap.NetworkMap + logger *log.Logger +} + +// NewGossip initializes gossip to maintain the given network map. +func NewGossip(netmap *netmap.NetworkMap, logger *log.Logger) *Gossip { + return &Gossip{ + netmap: netmap, + logger: logger.WithSubsystem("gossip"), + } +} + +// Run gossips with the other nodes in the cluster until cancelled. +func (g *Gossip) Run(_ context.Context) error { + g.logger.Info("starting gossip") + return nil +} diff --git a/server/netmap/netmap.go b/server/netmap/netmap.go new file mode 100644 index 00000000..b09d2c13 --- /dev/null +++ b/server/netmap/netmap.go @@ -0,0 +1,13 @@ +package netmap + +// NetworkMap represents the known state of the cluster as seen by the local +// node. +// +// This map is eventually consistent. The state is propagated among the nodes +// in the cluster using gossip. +type NetworkMap struct { +} + +func NewNetworkMap() *NetworkMap { + return &NetworkMap{} +} diff --git a/server/netmap/node.go b/server/netmap/node.go new file mode 100644 index 00000000..3947327a --- /dev/null +++ b/server/netmap/node.go @@ -0,0 +1,17 @@ +package netmap + +// Node represents the known state about a node in the cluster. +type Node struct { + // ID is a unique identifier for the node in the cluster. + ID string + + // HTTPAddr is the advertised HTTP address + HTTPAddr string + + // GossipAddr is the advertised gossip address. + GossipAddr string + + // Endpoints contains the active endpoints on the node. This maps the + // active endpoint ID to the number of listeners for that endpoint. + Endpoints map[string]int +}