diff --git a/README.md b/README.md index fc271ea..03f9e9c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A really tiny KV store. ## Building from source The repository build system outputs binaries for both the server and the CLI. Additionally, OCI containers are also -build for multiple architectures. +built for multiple architectures. ```shell bazelisk build //... diff --git a/server/bbolt/BUILD.bazel b/server/bbolt/BUILD.bazel new file mode 100644 index 0000000..df534b6 --- /dev/null +++ b/server/bbolt/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "bbolt", + srcs = [ + "bbolt.go", + "utils.go", + ], + importpath = "github.com/c16a/pouch/server/bbolt", + visibility = ["//visibility:public"], + deps = [ + "@com_github_hashicorp_go_msgpack_v2//codec", + "@com_github_hashicorp_raft//:raft", + "@io_etcd_go_bbolt//:bbolt", + ], +) diff --git a/server/store/bbolt.go b/server/bbolt/bbolt.go similarity index 98% rename from server/store/bbolt.go rename to server/bbolt/bbolt.go index a9c53fe..ec55508 100644 --- a/server/store/bbolt.go +++ b/server/bbolt/bbolt.go @@ -1,4 +1,4 @@ -package store +package bbolt import ( "errors" @@ -17,7 +17,7 @@ var ( dbLogs = []byte("logs") dbConf = []byte("conf") - // An error indicating a given key does not exist + // ErrKeyNotFound is an error indicating a given key does not exist ErrKeyNotFound = errors.New("not found") ) diff --git a/server/store/utils.go b/server/bbolt/utils.go similarity index 98% rename from server/store/utils.go rename to server/bbolt/utils.go index ce133c3..3aeb753 100644 --- a/server/store/utils.go +++ b/server/bbolt/utils.go @@ -1,4 +1,4 @@ -package store +package bbolt import ( "bytes" diff --git a/server/handlers/BUILD.bazel b/server/handlers/BUILD.bazel index 7fd7dda..c66a9eb 100644 --- a/server/handlers/BUILD.bazel +++ b/server/handlers/BUILD.bazel @@ -16,5 +16,6 @@ go_library( "//server/store", "@com_github_gorilla_websocket//:websocket", "@com_github_quic_go_quic_go//:quic-go", + "@org_uber_go_zap//:zap", ], ) diff --git a/server/handlers/net.go b/server/handlers/net.go index ac12367..76e0cad 100644 --- a/server/handlers/net.go +++ b/server/handlers/net.go @@ -6,30 +6,39 @@ import ( "github.com/c16a/pouch/sdk/auth" "github.com/c16a/pouch/sdk/commands" "github.com/c16a/pouch/server/store" + "go.uber.org/zap" "io" - "log" "net" "strings" ) func StartTcpListener(node *store.RaftNode) { + logger := node.GetLogger() if node.Config.Tcp != nil && node.Config.Tcp.Enabled { startNetListener(node, "tcp", node.Config.Tcp.Addr) + } else { + logger.Warn("skipping TCP listener") } } func StartUnixListener(node *store.RaftNode) { + logger := node.GetLogger() if node.Config.Unix != nil && node.Config.Unix.Enabled { startNetListener(node, "unix", node.Config.Unix.Path) + } else { + logger.Warn("skipping Unix listener") } } func startNetListener(node *store.RaftNode, protocol string, addr string) { + logger := node.GetLogger() + var listener net.Listener var err error tlsConfig, err := GetTlsConfig(node.Config) if err != nil { - log.Fatal(err) + logger.Error("failed to load TLS config", zap.Error(err)) + return } else { if tlsConfig != nil { listener, err = tls.Listen(protocol, addr, tlsConfig) @@ -38,7 +47,8 @@ func startNetListener(node *store.RaftNode, protocol string, addr string) { } } if err != nil { - log.Fatal(err) + logger.Error("failed to start net listener", zap.String("protocol", protocol), zap.Error(err)) + return } for { diff --git a/server/handlers/quic.go b/server/handlers/quic.go index e3ea6b2..9e013d0 100644 --- a/server/handlers/quic.go +++ b/server/handlers/quic.go @@ -6,13 +6,16 @@ import ( "github.com/c16a/pouch/sdk/commands" "github.com/c16a/pouch/server/store" "github.com/quic-go/quic-go" + "go.uber.org/zap" "io" - "log" "strings" ) func StartQuicListener(node *store.RaftNode) { + logger := node.GetLogger() + if node.Config.Quic == nil || !node.Config.Quic.Enabled { + logger.Warn("skipping quic listener") return } @@ -22,17 +25,17 @@ func StartQuicListener(node *store.RaftNode) { var err error tlsConfig, err := GetTlsConfig(node.Config) if err != nil { - log.Fatal(err) + logger.Fatal("failed to load TLS config", zap.Error(err)) } else { if tlsConfig != nil { listener, err = quic.ListenAddr(quicAddr, tlsConfig, nil) } else { - log.Fatal("cannot start QUIC listener without TLSConfig") + logger.Fatal("cannot start QUIC listener without TLSConfig") } } if err != nil { - log.Fatal(err) + logger.Error("failed to start net listener", zap.String("protocol", "quic"), zap.Error(err)) } for { diff --git a/server/handlers/ws.go b/server/handlers/ws.go index 0dffc5d..007f53b 100644 --- a/server/handlers/ws.go +++ b/server/handlers/ws.go @@ -4,12 +4,15 @@ import ( "github.com/c16a/pouch/sdk/commands" "github.com/c16a/pouch/server/store" "github.com/gorilla/websocket" + "go.uber.org/zap" "log" "net/http" "strings" ) func StartWsListener(node *store.RaftNode) { + logger := node.GetLogger() + if node.Config.Ws == nil || !node.Config.Ws.Enabled { return } @@ -24,7 +27,7 @@ func StartWsListener(node *store.RaftNode) { tlsConfig, err := GetTlsConfig(node.Config) if err != nil { - log.Fatal(err) + logger.Error("failed to load tls config", zap.Error(err)) } else { if tlsConfig != nil { server.TLSConfig = tlsConfig @@ -34,7 +37,7 @@ func StartWsListener(node *store.RaftNode) { go func() { err := server.ListenAndServe() if err != nil { - log.Fatal(err) + logger.Error("failed to start http server", zap.Error(err)) } }() } diff --git a/server/store/BUILD.bazel b/server/store/BUILD.bazel index d3ea477..24239f4 100644 --- a/server/store/BUILD.bazel +++ b/server/store/BUILD.bazel @@ -3,7 +3,6 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "store", srcs = [ - "bbolt.go", "config.go", "lists.go", "node.go", @@ -11,17 +10,15 @@ go_library( "sets.go", "snap_shot.go", "store.go", - "utils.go", ], importpath = "github.com/c16a/pouch/server/store", visibility = ["//visibility:public"], deps = [ "//sdk/commands", + "//server/bbolt", "//server/datatypes", "@com_github_google_uuid//:uuid", - "@com_github_hashicorp_go_msgpack_v2//codec", "@com_github_hashicorp_raft//:raft", - "@io_etcd_go_bbolt//:bbolt", "@org_uber_go_zap//:zap", "@org_uber_go_zap//zapio", ], diff --git a/server/store/node.go b/server/store/node.go index 7f22076..e28cec3 100644 --- a/server/store/node.go +++ b/server/store/node.go @@ -5,13 +5,13 @@ import ( "errors" "fmt" "github.com/c16a/pouch/sdk/commands" + "github.com/c16a/pouch/server/bbolt" "github.com/c16a/pouch/server/datatypes" "github.com/google/uuid" "github.com/hashicorp/raft" "go.uber.org/zap" "go.uber.org/zap/zapio" "io" - "log" "net" "os" "path/filepath" @@ -37,25 +37,25 @@ type RaftNode struct { func NewRaftNode(config *NodeConfig, logger *zap.Logger) *RaftNode { raftPath := config.Cluster.RaftDir if raftPath == "" { - log.Fatalf("No raft dir specified") + logger.Fatal("no raft dir specified") } raftAddr := config.Cluster.Addr if raftAddr == "" { - log.Fatalf("No raft addr specified") + logger.Fatal("no raft addr specified") } nodeId := config.Cluster.NodeID if nodeId == "" { id, err := uuid.NewV7() if err != nil { - log.Fatalf("failed to generate node id: %s", err.Error()) + logger.Fatal("failed to generate node id", zap.Error(err)) } config.Cluster.NodeID = id.String() } if err := os.MkdirAll(raftPath, 0700); err != nil { - log.Fatalf("failed to create path for Raft storage: %s", err.Error()) + logger.Fatal("failed to create path for Raft storage", zap.Error(err)) } return &RaftNode{ @@ -67,6 +67,10 @@ func NewRaftNode(config *NodeConfig, logger *zap.Logger) *RaftNode { } } +func (node *RaftNode) GetLogger() *zap.Logger { + return node.logger +} + // Start opens the store. If enableSingle is set, and there are no existing peers, // then this node becomes the first node, and therefore leader, of the cluster. // localID should be the server identifier for this node. @@ -94,7 +98,7 @@ func (node *RaftNode) Start() error { } // Create the log store and stable store. - boltDB, err := NewBoltStore(filepath.Join(node.RaftDir, "raft.db")) + boltDB, err := bbolt.NewBoltStore(filepath.Join(node.RaftDir, "raft.db")) if err != nil { return fmt.Errorf("new bbolt store: %s", err) } @@ -162,7 +166,7 @@ func (node *RaftNode) ApplyCmd(cmd commands.Command) string { case commands.SUnion: return node.SUnion(cmd.(*commands.SUnionCommand)) default: - return (&commands.ErrorResponse{Err: errors.New("unknown command")}).String() + return (&commands.ErrorResponse{Err: commands.ErrInvalidCommand}).String() } } @@ -409,7 +413,7 @@ func (node *RaftNode) dialPeer(peerAddr string) error { func (node *RaftNode) startPeeringServer() error { peeringPort := node.Config.Cluster.Addr if peeringPort == "" { - log.Fatalf("Raft addr not specified") + node.logger.Fatal("raft addr not specified") } udpAddr, err := net.ResolveUDPAddr("udp", peeringPort)