diff --git a/cmd/serve.go b/cmd/serve.go index 9c6e1b5..c38d75b 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -9,7 +9,6 @@ import ( "net/http" "os" "os/signal" - "time" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -24,11 +23,6 @@ import ( dbutils "github.com/infratographer/fertilesoil/storage/crdb/utils" ) -const ( - defaultListen = ":8080" - defaultServerShutdownTimeout = 5 * time.Second -) - // serveCmd represents the treemanager command. var serveCmd = &cobra.Command{ Use: "serve", @@ -48,18 +42,36 @@ func init() { v := viper.GetViper() dbutils.RegisterDBArgs(v, serveCmd.Flags()) - ginx.MustViperFlags(v, serveCmd.Flags(), defaultListen) + ginx.MustViperFlags(v, serveCmd.Flags(), treemanager.DefaultTreeManagerListen) loggingx.MustViperFlags(v, serveCmd.Flags()) natsutils.RegisterNATSArgs(v, serveCmd.Flags()) + // TODO(jaosorior): Add tracing + // TODO(jaosorior): Add metrics + // TODO(jaosorior): Add TLS flags + // Server flags flags := serveCmd.Flags() + + // server shutdown timeout flags.Duration("server-shutdown-timeout", - defaultServerShutdownTimeout, + treemanager.DefaultTreeManagerShutdownTimeout, "Time to wait for the server to shutdown gracefully") viperx.MustBindFlag(v, "server.shutdown", flags.Lookup("server-shutdown-timeout")) - flags.String("server-unix-socket", "", "Listen on a unix socket instead of a TCP socket.") + + // server UNIX socket + flags.String("server-unix-socket", + treemanager.DefaultTreeManagerUnix, + "Listen on a unix socket instead of a TCP socket.") viperx.MustBindFlag(v, "server.unix_socket", flags.Lookup("server-unix-socket")) + + // read-only mode + flags.Bool("read-only", treemanager.DefaultTreeManagerReadOnly, "Run the server in read-only mode.") + viperx.MustBindFlag(v, "server.read_only", flags.Lookup("read-only")) + + // fast reads + flags.Bool("fast-reads", treemanager.DefaultTreeManagerFastReads, "Run the server in fast reads mode.") + viperx.MustBindFlag(v, "server.fast_reads", flags.Lookup("fast-reads")) } func serverRunE(cmd *cobra.Command, args []string) error { @@ -99,12 +111,14 @@ func serverRunE(cmd *cobra.Command, args []string) error { s := treemanager.NewServer( l, - viper.GetString("listen"), db, - viper.GetBool("debug"), - viper.GetDuration("server.shutdown"), - viper.GetString("server.unix_socket"), - notif, + treemanager.WithListen(v.GetString("server.listen")), + treemanager.WithUnix(v.GetString("server.unix_socket")), + treemanager.WithDebug(v.GetBool("debug")), + treemanager.WithReadOnly(v.GetBool("server.read_only")), + treemanager.WithFastReads(v.GetBool("server.fast_reads")), + treemanager.WithShutdownTimeout(v.GetDuration("server.shutdown")), + treemanager.WithNotifier(notif), ) go func() { diff --git a/go.sum b/go.sum index 18f7fd2..0073448 100644 --- a/go.sum +++ b/go.sum @@ -84,7 +84,6 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/zap v0.1.0 h1:RMSFFJo34XZogV62OgOzvrlaMNmXrNxmJ3bFmMwl6Cc= github.com/gin-contrib/zap v0.1.0/go.mod h1:hvnZaPs478H1PGvRP8w89ZZbyJUiyip4ddiI/53WG3o= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398= @@ -305,8 +304,6 @@ github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI= github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= github.com/nats-io/nats-server/v2 v2.9.10 h1:LMC46Oi9E6BUx/xBsaCVZgofliAqKQzRPU6eKWkN8jE= github.com/nats-io/nats-server/v2 v2.9.10/go.mod h1:AB6hAnGZDlYfqb7CTAm66ZKMZy9DpfierY1/PbpvI2g= -github.com/nats-io/nats.go v1.22.0 h1:3dxyVf+S449DbMriqQV27HgSbXklxT9SUKbDKIxhrV0= -github.com/nats-io/nats.go v1.22.0/go.mod h1:tLqubohF7t4z3du1QDPYJIQQyhb4wl6DhjxEajSI7UA= github.com/nats-io/nats.go v1.22.1 h1:XzfqDspY0RNufzdrB8c4hFR+R3dahkxlpWe5+IWJzbE= github.com/nats-io/nats.go v1.22.1/go.mod h1:tLqubohF7t4z3du1QDPYJIQQyhb4wl6DhjxEajSI7UA= github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= diff --git a/internal/httpsrv/treemanager/config.go b/internal/httpsrv/treemanager/config.go new file mode 100644 index 0000000..48639f6 --- /dev/null +++ b/internal/httpsrv/treemanager/config.go @@ -0,0 +1,100 @@ +package treemanager + +import ( + "time" + + "github.com/infratographer/fertilesoil/notifier" + "github.com/infratographer/fertilesoil/notifier/noop" + "github.com/infratographer/fertilesoil/storage/crdb/driver" +) + +type treeManagerConfig struct { + listen string + unix string + debug bool + readonly bool + fastReads bool + shutdownTimeout time.Duration + notif notifier.Notifier +} + +type Option func(*treeManagerConfig) + +// WithListen sets the listen address for the server. +func WithListen(listen string) Option { + return func(c *treeManagerConfig) { + c.listen = listen + } +} + +// WithUnix sets the unix socket for the server. +// If set, the server will listen on the unix socket +// instead of the listen address. +func WithUnix(unix string) Option { + return func(c *treeManagerConfig) { + c.unix = unix + } +} + +// WithDebug sets the debug flag for the server. +func WithDebug(debug bool) Option { + return func(c *treeManagerConfig) { + c.debug = debug + } +} + +// WithReadOnly sets the readonly flag for the server. +// If true, the server will use the readonly flag when +// reading from the database. +func WithReadOnly(readonly bool) Option { + return func(c *treeManagerConfig) { + c.readonly = readonly + } +} + +// WithFastReads sets the fastReads flag for the server. +// If true, the server will use the fastReads flag when +// reading from the database. This will cause the server +// to read from the database without waiting for the +// database to commit the transaction. This is useful +// for read-heavy workloads, but can cause data to be +// out of sync with the database. +func WithFastReads(fastReads bool) Option { + return func(c *treeManagerConfig) { + c.fastReads = fastReads + } +} + +// WithShutdownTimeout sets the shutdown timeout for the server. +func WithShutdownTimeout(t time.Duration) Option { + return func(c *treeManagerConfig) { + c.shutdownTimeout = t + } +} + +// WithNotifier sets the notifier for the server. +func WithNotifier(n notifier.Notifier) Option { + return func(c *treeManagerConfig) { + if n == nil { + n = noop.NewNotifier() + } + c.notif = n + } +} + +func (c *treeManagerConfig) apply(opts ...Option) { + for _, opt := range opts { + opt(c) + } +} + +func (c *treeManagerConfig) withStorageDriverOptions() []driver.Options { + opts := []driver.Options{} + if c.readonly { + opts = append(opts, driver.WithReadOnly()) + } + if c.fastReads { + opts = append(opts, driver.WithFastReads()) + } + return opts +} diff --git a/internal/httpsrv/treemanager/defaults.go b/internal/httpsrv/treemanager/defaults.go new file mode 100644 index 0000000..2c0ecc1 --- /dev/null +++ b/internal/httpsrv/treemanager/defaults.go @@ -0,0 +1,25 @@ +package treemanager + +import ( + "time" + + "github.com/infratographer/fertilesoil/notifier/noop" +) + +const ( + // DefaultTreeManagerListen is the default listen address for the TreeManager. + DefaultTreeManagerListen = ":8080" + // DefaultTreeManagerUnix is the default unix socket for the TreeManager. + DefaultTreeManagerUnix = "" + // DefaultTreeManagerDebug is the default debug flag for the TreeManager. + DefaultTreeManagerDebug = false + // DefaultTreeManagerReadOnly is the default read-only flag for the TreeManager. + DefaultTreeManagerReadOnly = false + // DefaultTreeManagerFastReads is the default fast reads flag for the TreeManager. + DefaultTreeManagerFastReads = false + // DefaultTreeManagerShutdownTimeout is the default shutdown timeout for the TreeManager. + DefaultTreeManagerShutdownTimeout = 5 * time.Second +) + +// DefaultTreeManagerNotifier is the default notifier for the TreeManager. +var DefaultTreeManagerNotifier = noop.NewNotifier() diff --git a/internal/httpsrv/treemanager/treemanager.go b/internal/httpsrv/treemanager/treemanager.go index 19fa7bf..b88c225 100644 --- a/internal/httpsrv/treemanager/treemanager.go +++ b/internal/httpsrv/treemanager/treemanager.go @@ -5,15 +5,12 @@ import ( "database/sql" "errors" "net/http" - "time" "github.com/gin-gonic/gin" "go.uber.org/zap" v1 "github.com/infratographer/fertilesoil/api/v1" "github.com/infratographer/fertilesoil/internal/httpsrv/common" - "github.com/infratographer/fertilesoil/notifier" - "github.com/infratographer/fertilesoil/notifier/noop" "github.com/infratographer/fertilesoil/storage" "github.com/infratographer/fertilesoil/storage/crdb/driver" sn "github.com/infratographer/fertilesoil/storage/notifier" @@ -21,25 +18,25 @@ import ( func NewServer( logger *zap.Logger, - listen string, db *sql.DB, - debug bool, - shutdownTime time.Duration, - unix string, - n notifier.Notifier, + opts ...Option, ) *common.Server { - dbdrv := driver.NewDirectoryDriver(db) + cfg := &treeManagerConfig{ + listen: DefaultTreeManagerListen, + unix: DefaultTreeManagerUnix, + debug: DefaultTreeManagerDebug, + readonly: DefaultTreeManagerReadOnly, + fastReads: DefaultTreeManagerFastReads, + shutdownTimeout: DefaultTreeManagerShutdownTimeout, + notif: DefaultTreeManagerNotifier, + } + cfg.apply(opts...) - var notif notifier.Notifier + dbdrv := driver.NewDirectoryDriver(db, cfg.withStorageDriverOptions()...) - if n == nil { - notif = noop.NewNotifier() - } else { - notif = n - } + store := sn.StorageWithNotifier(dbdrv, cfg.notif, sn.WithNotifyRetrier()) - store := sn.StorageWithNotifier(dbdrv, notif, sn.WithNotifyRetrier()) - s := common.NewServer(logger, listen, db, store, debug, shutdownTime, unix) + s := common.NewServer(logger, cfg.listen, db, store, cfg.debug, cfg.shutdownTimeout, cfg.unix) s.SetHandler(newHandler(logger, s)) diff --git a/tests/integration/client_test.go b/tests/integration/client_test.go index 637eb08..a55fa9d 100644 --- a/tests/integration/client_test.go +++ b/tests/integration/client_test.go @@ -348,7 +348,14 @@ func TestServerWithBadDB(t *testing.T) { dbconn, err := sql.Open("postgres", baseDBURL.String()) assert.NoError(t, err, "error creating db connection") - srv := treemanager.NewServer(tl, srvhost, dbconn, debug, defaultShutdownTime, skt, nil) + srv := treemanager.NewServer( + tl, + dbconn, + treemanager.WithListen(srvhost), + treemanager.WithDebug(debug), + treemanager.WithShutdownTimeout(defaultShutdownTime), + treemanager.WithUnix(skt), + ) defer func() { err := srv.Shutdown() diff --git a/tests/integration/helpers_test.go b/tests/integration/helpers_test.go index 00268c6..a908798 100644 --- a/tests/integration/helpers_test.go +++ b/tests/integration/helpers_test.go @@ -81,7 +81,15 @@ func newTestServerWithNotifier(t *testing.T, skt string, notif notifier.Notifier gooseDBMutex.Unlock() - tm := treemanager.NewServer(tl, srvhost, dbconn, debug, defaultShutdownTime, skt, notif) + tm := treemanager.NewServer( + tl, + dbconn, + treemanager.WithListen(srvhost), + treemanager.WithDebug(debug), + treemanager.WithShutdownTimeout(defaultShutdownTime), + treemanager.WithUnix(skt), + treemanager.WithNotifier(notif), + ) return tm }