From 51d229b02505df770ed891ec8ab20843bc2b1d1d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 1 Sep 2022 14:15:41 +0100 Subject: [PATCH] Configuration tweaks (#2567) This makes the following changes: * The various `Defaults` functions are now responsible for setting sane defaults if `generate` is specified, rather than hiding them in `generate-config` * Some configuration options have been marked as `omitempty` so that they don't appear in generated configs unnecessarily (monolith-specific vs. polylith-specific options) * A new option `-polylith` has been added to `generate-config` to create a config that makes sense for polylith deployments (i.e. including the internal/external API listeners and per-component database sections) * A new option `-normalise` has been added to `generate-config` to take an existing file and add any missing options and/or defaults --- build/gobind-pinecone/monolith.go | 5 +- build/gobind-yggdrasil/monolith.go | 5 +- build/scripts/ComplementPostgres.Dockerfile | 7 +- clientapi/routing/register_test.go | 5 +- cmd/dendrite-demo-pinecone/main.go | 5 +- cmd/dendrite-demo-yggdrasil/main.go | 5 +- cmd/generate-config/main.go | 150 +++++++++----------- federationapi/federationapi_keys_test.go | 5 +- federationapi/federationapi_test.go | 5 +- setup/config/config.go | 33 +++-- setup/config/config_appservice.go | 10 +- setup/config/config_clientapi.go | 16 ++- setup/config/config_federationapi.go | 45 ++++-- setup/config/config_global.go | 32 +++-- setup/config/config_jetstream.go | 4 +- setup/config/config_keyserver.go | 26 ++-- setup/config/config_mediaapi.go | 47 ++++-- setup/config/config_mscs.go | 17 ++- setup/config/config_roomserver.go | 26 ++-- setup/config/config_syncapi.go | 30 ++-- setup/config/config_userapi.go | 26 ++-- setup/mscs/msc2836/msc2836_test.go | 5 +- test/testrig/base.go | 25 +++- 23 files changed, 322 insertions(+), 212 deletions(-) diff --git a/build/gobind-pinecone/monolith.go b/build/gobind-pinecone/monolith.go index 60e81721..44eab4cd 100644 --- a/build/gobind-pinecone/monolith.go +++ b/build/gobind-pinecone/monolith.go @@ -243,7 +243,10 @@ func (m *DendriteMonolith) Start() { prefix := hex.EncodeToString(pk) cfg := &config.Dendrite{} - cfg.Defaults(true) + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) cfg.Global.ServerName = gomatrixserverlib.ServerName(hex.EncodeToString(pk)) cfg.Global.PrivateKey = sk cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID) diff --git a/build/gobind-yggdrasil/monolith.go b/build/gobind-yggdrasil/monolith.go index 4432a3a4..896f3d14 100644 --- a/build/gobind-yggdrasil/monolith.go +++ b/build/gobind-yggdrasil/monolith.go @@ -82,7 +82,10 @@ func (m *DendriteMonolith) Start() { m.YggdrasilNode = ygg cfg := &config.Dendrite{} - cfg.Defaults(true) + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) cfg.Global.ServerName = gomatrixserverlib.ServerName(ygg.DerivedServerName()) cfg.Global.PrivateKey = ygg.PrivateKey() cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID) diff --git a/build/scripts/ComplementPostgres.Dockerfile b/build/scripts/ComplementPostgres.Dockerfile index 69954012..785090b0 100644 --- a/build/scripts/ComplementPostgres.Dockerfile +++ b/build/scripts/ComplementPostgres.Dockerfile @@ -46,9 +46,8 @@ EXPOSE 8008 8448 # At runtime, generate TLS cert based on the CA now mounted at /ca # At runtime, replace the SERVER_NAME with what we are told CMD /build/run_postgres.sh && ./generate-keys --keysize 1024 --server $SERVER_NAME --tls-cert server.crt --tls-key server.key --tls-authority-cert /complement/ca/ca.crt --tls-authority-key /complement/ca/ca.key && \ - ./generate-config -server $SERVER_NAME --ci > dendrite.yaml && \ - # Replace the connection string with a single postgres DB, using user/db = 'postgres' and no password, bump max_conns - sed -i "s%connection_string:.*$%connection_string: postgresql://postgres@localhost/postgres?sslmode=disable%g" dendrite.yaml && \ - sed -i 's/max_open_conns:.*$/max_open_conns: 100/g' dendrite.yaml && \ + ./generate-config -server $SERVER_NAME --ci --db postgresql://postgres@localhost/postgres?sslmode=disable > dendrite.yaml && \ + # Bump max_open_conns up here in the global database config + sed -i 's/max_open_conns:.*$/max_open_conns: 1990/g' dendrite.yaml && \ cp /complement/ca/ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates && \ exec ./dendrite-monolith-server --really-enable-open-registration --tls-cert server.crt --tls-key server.key --config dendrite.yaml -api=${API:-0} \ No newline at end of file diff --git a/clientapi/routing/register_test.go b/clientapi/routing/register_test.go index 0507116f..85846c7d 100644 --- a/clientapi/routing/register_test.go +++ b/clientapi/routing/register_test.go @@ -181,7 +181,10 @@ func TestValidationOfApplicationServices(t *testing.T) { // Set up a config fakeConfig := &config.Dendrite{} - fakeConfig.Defaults(true) + fakeConfig.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) fakeConfig.Global.ServerName = "localhost" fakeConfig.ClientAPI.Derived.ApplicationServices = []config.ApplicationService{fakeApplicationService} diff --git a/cmd/dendrite-demo-pinecone/main.go b/cmd/dendrite-demo-pinecone/main.go index 52c9dc8e..83b52132 100644 --- a/cmd/dendrite-demo-pinecone/main.go +++ b/cmd/dendrite-demo-pinecone/main.go @@ -115,7 +115,10 @@ func main() { panic("failed to load PEM key: " + err.Error()) } } - cfg.Defaults(true) + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) cfg.Global.PrivateKey = sk cfg.Global.JetStream.StoragePath = config.Path(fmt.Sprintf("%s/", *instanceName)) cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-account.db", *instanceName)) diff --git a/cmd/dendrite-demo-yggdrasil/main.go b/cmd/dendrite-demo-yggdrasil/main.go index 086baa26..d2fddf8b 100644 --- a/cmd/dendrite-demo-yggdrasil/main.go +++ b/cmd/dendrite-demo-yggdrasil/main.go @@ -78,7 +78,10 @@ func main() { if configFlagSet { cfg = setup.ParseFlags(true) } else { - cfg.Defaults(true) + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) cfg.Global.JetStream.StoragePath = config.Path(fmt.Sprintf("%s/", *instanceName)) cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-account.db", *instanceName)) cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mediaapi.db", *instanceName)) diff --git a/cmd/generate-config/main.go b/cmd/generate-config/main.go index 6ae3ff9c..c24e8153 100644 --- a/cmd/generate-config/main.go +++ b/cmd/generate-config/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "path/filepath" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrixserverlib" @@ -11,90 +12,81 @@ import ( ) func main() { - defaultsForCI := flag.Bool("ci", false, "sane defaults for CI testing") + defaultsForCI := flag.Bool("ci", false, "Populate the configuration with sane defaults for use in CI") serverName := flag.String("server", "", "The domain name of the server if not 'localhost'") - dbURI := flag.String("db", "", "The DB URI to use for all components if not SQLite files") + dbURI := flag.String("db", "", "The DB URI to use for all components (PostgreSQL only)") + dirPath := flag.String("dir", "./", "The folder to use for paths (like SQLite databases, media storage)") + normalise := flag.String("normalise", "", "Normalise an existing configuration file by adding new/missing options and defaults") + polylith := flag.Bool("polylith", false, "Generate a config that makes sense for polylith deployments") flag.Parse() - cfg := &config.Dendrite{ - Version: config.Version, - } - cfg.Defaults(true) - if *serverName != "" { - cfg.Global.ServerName = gomatrixserverlib.ServerName(*serverName) - } - if *dbURI != "" { - cfg.FederationAPI.Database.ConnectionString = config.DataSource(*dbURI) - cfg.KeyServer.Database.ConnectionString = config.DataSource(*dbURI) - cfg.MSCs.Database.ConnectionString = config.DataSource(*dbURI) - cfg.MediaAPI.Database.ConnectionString = config.DataSource(*dbURI) - cfg.RoomServer.Database.ConnectionString = config.DataSource(*dbURI) - cfg.SyncAPI.Database.ConnectionString = config.DataSource(*dbURI) - cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(*dbURI) - } - cfg.Global.TrustedIDServers = []string{ - "matrix.org", - "vector.im", - } - cfg.Logging = []config.LogrusHook{ - { - Type: "file", - Level: "info", - Params: map[string]interface{}{ - "path": "/var/log/dendrite", - }, - }, - } - cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{ - { - ServerName: "matrix.org", - Keys: []config.KeyPerspectiveTrustKey{ - { - KeyID: "ed25519:auto", - PublicKey: "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw", - }, - { - KeyID: "ed25519:a_RXGa", - PublicKey: "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ", + var cfg *config.Dendrite + if *normalise == "" { + cfg = &config.Dendrite{ + Version: config.Version, + } + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: !*polylith, + }) + if *serverName != "" { + cfg.Global.ServerName = gomatrixserverlib.ServerName(*serverName) + } + uri := config.DataSource(*dbURI) + if *polylith || uri.IsSQLite() || uri == "" { + for name, db := range map[string]*config.DatabaseOptions{ + "federationapi": &cfg.FederationAPI.Database, + "keyserver": &cfg.KeyServer.Database, + "mscs": &cfg.MSCs.Database, + "mediaapi": &cfg.MediaAPI.Database, + "roomserver": &cfg.RoomServer.Database, + "syncapi": &cfg.SyncAPI.Database, + "userapi": &cfg.UserAPI.AccountDatabase, + } { + if uri == "" { + path := filepath.Join(*dirPath, fmt.Sprintf("dendrite_%s.db", name)) + db.ConnectionString = config.DataSource(fmt.Sprintf("file:%s", path)) + } else { + db.ConnectionString = uri + } + } + } else { + cfg.Global.DatabaseOptions.ConnectionString = uri + } + cfg.Logging = []config.LogrusHook{ + { + Type: "file", + Level: "info", + Params: map[string]interface{}{ + "path": filepath.Join(*dirPath, "log"), }, }, - }, - } - cfg.MediaAPI.ThumbnailSizes = []config.ThumbnailSize{ - { - Width: 32, - Height: 32, - ResizeMethod: "crop", - }, - { - Width: 96, - Height: 96, - ResizeMethod: "crop", - }, - { - Width: 640, - Height: 480, - ResizeMethod: "scale", - }, - } - - if *defaultsForCI { - cfg.AppServiceAPI.DisableTLSValidation = true - cfg.ClientAPI.RateLimiting.Enabled = false - cfg.FederationAPI.DisableTLSValidation = false - // don't hit matrix.org when running tests!!! - cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{} - cfg.MSCs.MSCs = []string{"msc2836", "msc2946", "msc2444", "msc2753"} - cfg.Logging[0].Level = "trace" - cfg.Logging[0].Type = "std" - cfg.UserAPI.BCryptCost = bcrypt.MinCost - cfg.Global.JetStream.InMemory = true - cfg.ClientAPI.RegistrationDisabled = false - cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled = true - cfg.ClientAPI.RegistrationSharedSecret = "complement" - cfg.Global.Presence = config.PresenceOptions{ - EnableInbound: true, - EnableOutbound: true, + } + if *defaultsForCI { + cfg.AppServiceAPI.DisableTLSValidation = true + cfg.ClientAPI.RateLimiting.Enabled = false + cfg.FederationAPI.DisableTLSValidation = false + // don't hit matrix.org when running tests!!! + cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{} + cfg.MediaAPI.BasePath = config.Path(filepath.Join(*dirPath, "media")) + cfg.MSCs.MSCs = []string{"msc2836", "msc2946", "msc2444", "msc2753"} + cfg.Logging[0].Level = "trace" + cfg.Logging[0].Type = "std" + cfg.UserAPI.BCryptCost = bcrypt.MinCost + cfg.Global.JetStream.InMemory = true + cfg.Global.JetStream.StoragePath = config.Path(*dirPath) + cfg.ClientAPI.RegistrationDisabled = false + cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled = true + cfg.ClientAPI.RegistrationSharedSecret = "complement" + cfg.Global.Presence = config.PresenceOptions{ + EnableInbound: true, + EnableOutbound: true, + } + } + } else { + var err error + if cfg, err = config.Load(*normalise, !*polylith); err != nil { + panic(err) } } diff --git a/federationapi/federationapi_keys_test.go b/federationapi/federationapi_keys_test.go index 9c344622..4469da35 100644 --- a/federationapi/federationapi_keys_test.go +++ b/federationapi/federationapi_keys_test.go @@ -75,7 +75,10 @@ func TestMain(m *testing.M) { // Draw up just enough Dendrite config for the server key // API to work. cfg := &config.Dendrite{} - cfg.Defaults(true) + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) cfg.Global.ServerName = gomatrixserverlib.ServerName(s.name) cfg.Global.PrivateKey = testPriv cfg.Global.JetStream.InMemory = true diff --git a/federationapi/federationapi_test.go b/federationapi/federationapi_test.go index bdcb9f57..15f7a684 100644 --- a/federationapi/federationapi_test.go +++ b/federationapi/federationapi_test.go @@ -263,7 +263,10 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) { func TestRoomsV3URLEscapeDoNot404(t *testing.T) { _, privKey, _ := ed25519.GenerateKey(nil) cfg := &config.Dendrite{} - cfg.Defaults(true) + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) cfg.Global.KeyID = gomatrixserverlib.KeyID("ed25519:auto") cfg.Global.ServerName = gomatrixserverlib.ServerName("localhost") cfg.Global.PrivateKey = privKey diff --git a/setup/config/config.go b/setup/config/config.go index cc9c0447..5a618d67 100644 --- a/setup/config/config.go +++ b/setup/config/config.go @@ -211,7 +211,10 @@ func loadConfig( monolithic bool, ) (*Dendrite, error) { var c Dendrite - c.Defaults(false) + c.Defaults(DefaultOpts{ + Generate: false, + Monolithic: monolithic, + }) c.IsMonolith = monolithic var err error @@ -295,21 +298,25 @@ func (config *Dendrite) Derive() error { return nil } +type DefaultOpts struct { + Generate bool + Monolithic bool +} + // SetDefaults sets default config values if they are not explicitly set. -func (c *Dendrite) Defaults(generate bool) { +func (c *Dendrite) Defaults(opts DefaultOpts) { c.Version = Version - c.Global.Defaults(generate) - c.ClientAPI.Defaults(generate) - c.FederationAPI.Defaults(generate) - c.KeyServer.Defaults(generate) - c.MediaAPI.Defaults(generate) - c.RoomServer.Defaults(generate) - c.SyncAPI.Defaults(generate) - c.UserAPI.Defaults(generate) - c.AppServiceAPI.Defaults(generate) - c.MSCs.Defaults(generate) - + c.Global.Defaults(opts) + c.ClientAPI.Defaults(opts) + c.FederationAPI.Defaults(opts) + c.KeyServer.Defaults(opts) + c.MediaAPI.Defaults(opts) + c.RoomServer.Defaults(opts) + c.SyncAPI.Defaults(opts) + c.UserAPI.Defaults(opts) + c.AppServiceAPI.Defaults(opts) + c.MSCs.Defaults(opts) c.Wiring() } diff --git a/setup/config/config_appservice.go b/setup/config/config_appservice.go index 9c377127..bd21826f 100644 --- a/setup/config/config_appservice.go +++ b/setup/config/config_appservice.go @@ -29,7 +29,7 @@ type AppServiceAPI struct { Matrix *Global `yaml:"-"` Derived *Derived `yaml:"-"` // TODO: Nuke Derived from orbit - InternalAPI InternalAPIOptions `yaml:"internal_api"` + InternalAPI InternalAPIOptions `yaml:"internal_api,omitempty"` // DisableTLSValidation disables the validation of X.509 TLS certs // on appservice endpoints. This is not recommended in production! @@ -38,9 +38,11 @@ type AppServiceAPI struct { ConfigFiles []string `yaml:"config_files"` } -func (c *AppServiceAPI) Defaults(generate bool) { - c.InternalAPI.Listen = "http://localhost:7777" - c.InternalAPI.Connect = "http://localhost:7777" +func (c *AppServiceAPI) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.InternalAPI.Listen = "http://localhost:7777" + c.InternalAPI.Connect = "http://localhost:7777" + } } func (c *AppServiceAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { diff --git a/setup/config/config_clientapi.go b/setup/config/config_clientapi.go index ecf8f6bd..56f4b3f9 100644 --- a/setup/config/config_clientapi.go +++ b/setup/config/config_clientapi.go @@ -9,8 +9,8 @@ type ClientAPI struct { Matrix *Global `yaml:"-"` Derived *Derived `yaml:"-"` // TODO: Nuke Derived from orbit - InternalAPI InternalAPIOptions `yaml:"internal_api"` - ExternalAPI ExternalAPIOptions `yaml:"external_api"` + InternalAPI InternalAPIOptions `yaml:"internal_api,omitempty"` + ExternalAPI ExternalAPIOptions `yaml:"external_api,omitempty"` // If set disables new users from registering (except via shared // secrets) @@ -48,13 +48,15 @@ type ClientAPI struct { // Rate-limiting options RateLimiting RateLimiting `yaml:"rate_limiting"` - MSCs *MSCs `yaml:"mscs"` + MSCs *MSCs `yaml:"-"` } -func (c *ClientAPI) Defaults(generate bool) { - c.InternalAPI.Listen = "http://localhost:7771" - c.InternalAPI.Connect = "http://localhost:7771" - c.ExternalAPI.Listen = "http://[::]:8071" +func (c *ClientAPI) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.InternalAPI.Listen = "http://localhost:7771" + c.InternalAPI.Connect = "http://localhost:7771" + c.ExternalAPI.Listen = "http://[::]:8071" + } c.RegistrationSharedSecret = "" c.RecaptchaPublicKey = "" c.RecaptchaPrivateKey = "" diff --git a/setup/config/config_federationapi.go b/setup/config/config_federationapi.go index a7a515fd..d3a4b2b6 100644 --- a/setup/config/config_federationapi.go +++ b/setup/config/config_federationapi.go @@ -5,12 +5,12 @@ import "github.com/matrix-org/gomatrixserverlib" type FederationAPI struct { Matrix *Global `yaml:"-"` - InternalAPI InternalAPIOptions `yaml:"internal_api"` - ExternalAPI ExternalAPIOptions `yaml:"external_api"` + InternalAPI InternalAPIOptions `yaml:"internal_api,omitempty"` + ExternalAPI ExternalAPIOptions `yaml:"external_api,omitempty"` // The database stores information used by the federation destination queues to // send transactions to remote servers. - Database DatabaseOptions `yaml:"database"` + Database DatabaseOptions `yaml:"database,omitempty"` // Federation failure threshold. How many consecutive failures that we should // tolerate when sending federation requests to a specific server. The backoff @@ -30,25 +30,44 @@ type FederationAPI struct { PreferDirectFetch bool `yaml:"prefer_direct_fetch"` } -func (c *FederationAPI) Defaults(generate bool) { - c.InternalAPI.Listen = "http://localhost:7772" - c.InternalAPI.Connect = "http://localhost:7772" - c.ExternalAPI.Listen = "http://[::]:8072" +func (c *FederationAPI) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.InternalAPI.Listen = "http://localhost:7772" + c.InternalAPI.Connect = "http://localhost:7772" + c.ExternalAPI.Listen = "http://[::]:8072" + c.Database.Defaults(10) + } c.FederationMaxRetries = 16 c.DisableTLSValidation = false - c.Database.Defaults(10) - if generate { - c.Database.ConnectionString = "file:federationapi.db" + if opts.Generate { + c.KeyPerspectives = KeyPerspectives{ + { + ServerName: "matrix.org", + Keys: []KeyPerspectiveTrustKey{ + { + KeyID: "ed25519:auto", + PublicKey: "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw", + }, + { + KeyID: "ed25519:a_RXGa", + PublicKey: "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ", + }, + }, + }, + } + if !opts.Monolithic { + c.Database.ConnectionString = "file:federationapi.db" + } } } func (c *FederationAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - if c.Matrix.DatabaseOptions.ConnectionString == "" { - checkNotEmpty(configErrs, "federation_api.database.connection_string", string(c.Database.ConnectionString)) - } if isMonolith { // polylith required configs below return } + if c.Matrix.DatabaseOptions.ConnectionString == "" { + checkNotEmpty(configErrs, "federation_api.database.connection_string", string(c.Database.ConnectionString)) + } checkURL(configErrs, "federation_api.external_api.listen", string(c.ExternalAPI.Listen)) checkURL(configErrs, "federation_api.internal_api.listen", string(c.InternalAPI.Listen)) checkURL(configErrs, "federation_api.internal_api.connect", string(c.InternalAPI.Connect)) diff --git a/setup/config/config_global.go b/setup/config/config_global.go index d4e54e20..acc608dd 100644 --- a/setup/config/config_global.go +++ b/setup/config/config_global.go @@ -41,7 +41,7 @@ type Global struct { // connections will be used instead. This way we don't have to manage connection // counts on a per-component basis, but can instead do it for the entire monolith. // In a polylith deployment, this will be ignored. - DatabaseOptions DatabaseOptions `yaml:"database"` + DatabaseOptions DatabaseOptions `yaml:"database,omitempty"` // The server name to delegate server-server communications to, with optional port WellKnownServerName string `yaml:"well_known_server_name"` @@ -83,22 +83,28 @@ type Global struct { Cache Cache `yaml:"cache"` } -func (c *Global) Defaults(generate bool) { - if generate { +func (c *Global) Defaults(opts DefaultOpts) { + if opts.Generate { c.ServerName = "localhost" c.PrivateKeyPath = "matrix_key.pem" _, c.PrivateKey, _ = ed25519.GenerateKey(rand.New(rand.NewSource(0))) c.KeyID = "ed25519:auto" + c.TrustedIDServers = []string{ + "matrix.org", + "vector.im", + } } c.KeyValidityPeriod = time.Hour * 24 * 7 - - c.JetStream.Defaults(generate) - c.Metrics.Defaults(generate) + if opts.Monolithic { + c.DatabaseOptions.Defaults(90) + } + c.JetStream.Defaults(opts) + c.Metrics.Defaults(opts) c.DNSCache.Defaults() c.Sentry.Defaults() - c.ServerNotices.Defaults(generate) + c.ServerNotices.Defaults(opts) c.ReportStats.Defaults() - c.Cache.Defaults(generate) + c.Cache.Defaults() } func (c *Global) Verify(configErrs *ConfigErrors, isMonolith bool) { @@ -142,9 +148,9 @@ type Metrics struct { } `yaml:"basic_auth"` } -func (c *Metrics) Defaults(generate bool) { +func (c *Metrics) Defaults(opts DefaultOpts) { c.Enabled = false - if generate { + if opts.Generate { c.BasicAuth.Username = "metrics" c.BasicAuth.Password = "metrics" } @@ -166,8 +172,8 @@ type ServerNotices struct { RoomName string `yaml:"room_name"` } -func (c *ServerNotices) Defaults(generate bool) { - if generate { +func (c *ServerNotices) Defaults(opts DefaultOpts) { + if opts.Generate { c.Enabled = true c.LocalPart = "_server" c.DisplayName = "Server Alert" @@ -183,7 +189,7 @@ type Cache struct { MaxAge time.Duration `yaml:"max_age"` } -func (c *Cache) Defaults(generate bool) { +func (c *Cache) Defaults() { c.EstimatedMaxSize = 1024 * 1024 * 1024 // 1GB c.MaxAge = time.Hour } diff --git a/setup/config/config_jetstream.go b/setup/config/config_jetstream.go index a7827597..ef8bf014 100644 --- a/setup/config/config_jetstream.go +++ b/setup/config/config_jetstream.go @@ -31,10 +31,10 @@ func (c *JetStream) Durable(name string) string { return c.Prefixed(name) } -func (c *JetStream) Defaults(generate bool) { +func (c *JetStream) Defaults(opts DefaultOpts) { c.Addresses = []string{} c.TopicPrefix = "Dendrite" - if generate { + if opts.Generate { c.StoragePath = Path("./") c.NoLog = true c.DisableTLSValidation = true diff --git a/setup/config/config_keyserver.go b/setup/config/config_keyserver.go index 5f2f22c8..dca9ca9f 100644 --- a/setup/config/config_keyserver.go +++ b/setup/config/config_keyserver.go @@ -3,27 +3,31 @@ package config type KeyServer struct { Matrix *Global `yaml:"-"` - InternalAPI InternalAPIOptions `yaml:"internal_api"` + InternalAPI InternalAPIOptions `yaml:"internal_api,omitempty"` - Database DatabaseOptions `yaml:"database"` + Database DatabaseOptions `yaml:"database,omitempty"` } -func (c *KeyServer) Defaults(generate bool) { - c.InternalAPI.Listen = "http://localhost:7779" - c.InternalAPI.Connect = "http://localhost:7779" - c.Database.Defaults(10) - if generate { - c.Database.ConnectionString = "file:keyserver.db" +func (c *KeyServer) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.InternalAPI.Listen = "http://localhost:7779" + c.InternalAPI.Connect = "http://localhost:7779" + c.Database.Defaults(10) + } + if opts.Generate { + if !opts.Monolithic { + c.Database.ConnectionString = "file:keyserver.db" + } } } func (c *KeyServer) Verify(configErrs *ConfigErrors, isMonolith bool) { - if c.Matrix.DatabaseOptions.ConnectionString == "" { - checkNotEmpty(configErrs, "key_server.database.connection_string", string(c.Database.ConnectionString)) - } if isMonolith { // polylith required configs below return } + if c.Matrix.DatabaseOptions.ConnectionString == "" { + checkNotEmpty(configErrs, "key_server.database.connection_string", string(c.Database.ConnectionString)) + } checkURL(configErrs, "key_server.internal_api.listen", string(c.InternalAPI.Listen)) checkURL(configErrs, "key_server.internal_api.connect", string(c.InternalAPI.Connect)) } diff --git a/setup/config/config_mediaapi.go b/setup/config/config_mediaapi.go index 9717aa59..53a8219e 100644 --- a/setup/config/config_mediaapi.go +++ b/setup/config/config_mediaapi.go @@ -7,12 +7,12 @@ import ( type MediaAPI struct { Matrix *Global `yaml:"-"` - InternalAPI InternalAPIOptions `yaml:"internal_api"` - ExternalAPI ExternalAPIOptions `yaml:"external_api"` + InternalAPI InternalAPIOptions `yaml:"internal_api,omitempty"` + ExternalAPI ExternalAPIOptions `yaml:"external_api,omitempty"` // The MediaAPI database stores information about files uploaded and downloaded // by local users. It is only accessed by the MediaAPI. - Database DatabaseOptions `yaml:"database"` + Database DatabaseOptions `yaml:"database,omitempty"` // The base path to where the media files will be stored. May be relative or absolute. BasePath Path `yaml:"base_path"` @@ -38,23 +38,41 @@ type MediaAPI struct { // DefaultMaxFileSizeBytes defines the default file size allowed in transfers var DefaultMaxFileSizeBytes = FileSizeBytes(10485760) -func (c *MediaAPI) Defaults(generate bool) { - c.InternalAPI.Listen = "http://localhost:7774" - c.InternalAPI.Connect = "http://localhost:7774" - c.ExternalAPI.Listen = "http://[::]:8074" +func (c *MediaAPI) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.InternalAPI.Listen = "http://localhost:7774" + c.InternalAPI.Connect = "http://localhost:7774" + c.ExternalAPI.Listen = "http://[::]:8074" + c.Database.Defaults(5) + } c.MaxFileSizeBytes = DefaultMaxFileSizeBytes c.MaxThumbnailGenerators = 10 - c.Database.Defaults(5) - if generate { - c.Database.ConnectionString = "file:mediaapi.db" + if opts.Generate { + c.ThumbnailSizes = []ThumbnailSize{ + { + Width: 32, + Height: 32, + ResizeMethod: "crop", + }, + { + Width: 96, + Height: 96, + ResizeMethod: "crop", + }, + { + Width: 640, + Height: 480, + ResizeMethod: "scale", + }, + } + if !opts.Monolithic { + c.Database.ConnectionString = "file:mediaapi.db" + } c.BasePath = "./media_store" } } func (c *MediaAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - if c.Matrix.DatabaseOptions.ConnectionString == "" { - checkNotEmpty(configErrs, "media_api.database.connection_string", string(c.Database.ConnectionString)) - } checkNotEmpty(configErrs, "media_api.base_path", string(c.BasePath)) checkPositive(configErrs, "media_api.max_file_size_bytes", int64(c.MaxFileSizeBytes)) checkPositive(configErrs, "media_api.max_thumbnail_generators", int64(c.MaxThumbnailGenerators)) @@ -66,6 +84,9 @@ func (c *MediaAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { if isMonolith { // polylith required configs below return } + if c.Matrix.DatabaseOptions.ConnectionString == "" { + checkNotEmpty(configErrs, "media_api.database.connection_string", string(c.Database.ConnectionString)) + } checkURL(configErrs, "media_api.internal_api.listen", string(c.InternalAPI.Listen)) checkURL(configErrs, "media_api.internal_api.connect", string(c.InternalAPI.Connect)) checkURL(configErrs, "media_api.external_api.listen", string(c.ExternalAPI.Listen)) diff --git a/setup/config/config_mscs.go b/setup/config/config_mscs.go index b992f715..6d5ff39a 100644 --- a/setup/config/config_mscs.go +++ b/setup/config/config_mscs.go @@ -10,13 +10,17 @@ type MSCs struct { // 'msc2946': Spaces Summary - https://github.com/matrix-org/matrix-doc/pull/2946 MSCs []string `yaml:"mscs"` - Database DatabaseOptions `yaml:"database"` + Database DatabaseOptions `yaml:"database,omitempty"` } -func (c *MSCs) Defaults(generate bool) { - c.Database.Defaults(5) - if generate { - c.Database.ConnectionString = "file:mscs.db" +func (c *MSCs) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.Database.Defaults(5) + } + if opts.Generate { + if !opts.Monolithic { + c.Database.ConnectionString = "file:mscs.db" + } } } @@ -31,6 +35,9 @@ func (c *MSCs) Enabled(msc string) bool { } func (c *MSCs) Verify(configErrs *ConfigErrors, isMonolith bool) { + if isMonolith { // polylith required configs below + return + } if c.Matrix.DatabaseOptions.ConnectionString == "" { checkNotEmpty(configErrs, "mscs.database.connection_string", string(c.Database.ConnectionString)) } diff --git a/setup/config/config_roomserver.go b/setup/config/config_roomserver.go index bd6aa116..5e3b7f2e 100644 --- a/setup/config/config_roomserver.go +++ b/setup/config/config_roomserver.go @@ -3,27 +3,31 @@ package config type RoomServer struct { Matrix *Global `yaml:"-"` - InternalAPI InternalAPIOptions `yaml:"internal_api"` + InternalAPI InternalAPIOptions `yaml:"internal_api,omitempty"` - Database DatabaseOptions `yaml:"database"` + Database DatabaseOptions `yaml:"database,omitempty"` } -func (c *RoomServer) Defaults(generate bool) { - c.InternalAPI.Listen = "http://localhost:7770" - c.InternalAPI.Connect = "http://localhost:7770" - c.Database.Defaults(10) - if generate { - c.Database.ConnectionString = "file:roomserver.db" +func (c *RoomServer) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.InternalAPI.Listen = "http://localhost:7770" + c.InternalAPI.Connect = "http://localhost:7770" + c.Database.Defaults(20) + } + if opts.Generate { + if !opts.Monolithic { + c.Database.ConnectionString = "file:roomserver.db" + } } } func (c *RoomServer) Verify(configErrs *ConfigErrors, isMonolith bool) { - if c.Matrix.DatabaseOptions.ConnectionString == "" { - checkNotEmpty(configErrs, "room_server.database.connection_string", string(c.Database.ConnectionString)) - } if isMonolith { // polylith required configs below return } + if c.Matrix.DatabaseOptions.ConnectionString == "" { + checkNotEmpty(configErrs, "room_server.database.connection_string", string(c.Database.ConnectionString)) + } checkURL(configErrs, "room_server.internal_api.listen", string(c.InternalAPI.Listen)) checkURL(configErrs, "room_server.internal_ap.connect", string(c.InternalAPI.Connect)) } diff --git a/setup/config/config_syncapi.go b/setup/config/config_syncapi.go index 7d5e3808..4e302ae0 100644 --- a/setup/config/config_syncapi.go +++ b/setup/config/config_syncapi.go @@ -3,31 +3,35 @@ package config type SyncAPI struct { Matrix *Global `yaml:"-"` - InternalAPI InternalAPIOptions `yaml:"internal_api"` - ExternalAPI ExternalAPIOptions `yaml:"external_api"` + InternalAPI InternalAPIOptions `yaml:"internal_api,omitempty"` + ExternalAPI ExternalAPIOptions `yaml:"external_api,omitempty"` - Database DatabaseOptions `yaml:"database"` + Database DatabaseOptions `yaml:"database,omitempty"` RealIPHeader string `yaml:"real_ip_header"` } -func (c *SyncAPI) Defaults(generate bool) { - c.InternalAPI.Listen = "http://localhost:7773" - c.InternalAPI.Connect = "http://localhost:7773" - c.ExternalAPI.Listen = "http://localhost:8073" - c.Database.Defaults(10) - if generate { - c.Database.ConnectionString = "file:syncapi.db" +func (c *SyncAPI) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.InternalAPI.Listen = "http://localhost:7773" + c.InternalAPI.Connect = "http://localhost:7773" + c.ExternalAPI.Listen = "http://localhost:8073" + c.Database.Defaults(20) + } + if opts.Generate { + if !opts.Monolithic { + c.Database.ConnectionString = "file:syncapi.db" + } } } func (c *SyncAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - if c.Matrix.DatabaseOptions.ConnectionString == "" { - checkNotEmpty(configErrs, "sync_api.database", string(c.Database.ConnectionString)) - } if isMonolith { // polylith required configs below return } + if c.Matrix.DatabaseOptions.ConnectionString == "" { + checkNotEmpty(configErrs, "sync_api.database", string(c.Database.ConnectionString)) + } checkURL(configErrs, "sync_api.internal_api.listen", string(c.InternalAPI.Listen)) checkURL(configErrs, "sync_api.internal_api.connect", string(c.InternalAPI.Connect)) checkURL(configErrs, "sync_api.external_api.listen", string(c.ExternalAPI.Listen)) diff --git a/setup/config/config_userapi.go b/setup/config/config_userapi.go index d1e2b7fe..97a6d738 100644 --- a/setup/config/config_userapi.go +++ b/setup/config/config_userapi.go @@ -5,7 +5,7 @@ import "golang.org/x/crypto/bcrypt" type UserAPI struct { Matrix *Global `yaml:"-"` - InternalAPI InternalAPIOptions `yaml:"internal_api"` + InternalAPI InternalAPIOptions `yaml:"internal_api,omitempty"` // The cost when hashing passwords. BCryptCost int `yaml:"bcrypt_cost"` @@ -18,30 +18,34 @@ type UserAPI struct { // The Account database stores the login details and account information // for local users. It is accessed by the UserAPI. - AccountDatabase DatabaseOptions `yaml:"account_database"` + AccountDatabase DatabaseOptions `yaml:"account_database,omitempty"` } const DefaultOpenIDTokenLifetimeMS = 3600000 // 60 minutes -func (c *UserAPI) Defaults(generate bool) { - c.InternalAPI.Listen = "http://localhost:7781" - c.InternalAPI.Connect = "http://localhost:7781" +func (c *UserAPI) Defaults(opts DefaultOpts) { + if !opts.Monolithic { + c.InternalAPI.Listen = "http://localhost:7781" + c.InternalAPI.Connect = "http://localhost:7781" + c.AccountDatabase.Defaults(10) + } c.BCryptCost = bcrypt.DefaultCost c.OpenIDTokenLifetimeMS = DefaultOpenIDTokenLifetimeMS - c.AccountDatabase.Defaults(10) - if generate { - c.AccountDatabase.ConnectionString = "file:userapi_accounts.db" + if opts.Generate { + if !opts.Monolithic { + c.AccountDatabase.ConnectionString = "file:userapi_accounts.db" + } } } func (c *UserAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { checkPositive(configErrs, "user_api.openid_token_lifetime_ms", c.OpenIDTokenLifetimeMS) - if c.Matrix.DatabaseOptions.ConnectionString == "" { - checkNotEmpty(configErrs, "user_api.account_database.connection_string", string(c.AccountDatabase.ConnectionString)) - } if isMonolith { // polylith required configs below return } + if c.Matrix.DatabaseOptions.ConnectionString == "" { + checkNotEmpty(configErrs, "user_api.account_database.connection_string", string(c.AccountDatabase.ConnectionString)) + } checkURL(configErrs, "user_api.internal_api.listen", string(c.InternalAPI.Listen)) checkURL(configErrs, "user_api.internal_api.connect", string(c.InternalAPI.Connect)) } diff --git a/setup/mscs/msc2836/msc2836_test.go b/setup/mscs/msc2836/msc2836_test.go index 3e9d90a1..0388fcc5 100644 --- a/setup/mscs/msc2836/msc2836_test.go +++ b/setup/mscs/msc2836/msc2836_test.go @@ -547,7 +547,10 @@ func (r *testRoomserverAPI) QueryMembershipForUser(ctx context.Context, req *roo func injectEvents(t *testing.T, userAPI userapi.UserInternalAPI, rsAPI roomserver.RoomserverInternalAPI, events []*gomatrixserverlib.HeaderedEvent) *mux.Router { t.Helper() cfg := &config.Dendrite{} - cfg.Defaults(true) + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) cfg.Global.ServerName = "localhost" cfg.MSCs.Database.ConnectionString = "file:msc2836_test.db" cfg.MSCs.MSCs = []string{"msc2836"} diff --git a/test/testrig/base.go b/test/testrig/base.go index 33230921..9747ea60 100644 --- a/test/testrig/base.go +++ b/test/testrig/base.go @@ -30,12 +30,21 @@ import ( func CreateBaseDendrite(t *testing.T, dbType test.DBType) (*base.BaseDendrite, func()) { var cfg config.Dendrite - cfg.Defaults(false) + cfg.Defaults(config.DefaultOpts{ + Generate: false, + Monolithic: true, + }) cfg.Global.JetStream.InMemory = true switch dbType { case test.DBTypePostgres: - cfg.Global.Defaults(true) // autogen a signing key - cfg.MediaAPI.Defaults(true) // autogen a media path + cfg.Global.Defaults(config.DefaultOpts{ // autogen a signing key + Generate: true, + Monolithic: true, + }) + cfg.MediaAPI.Defaults(config.DefaultOpts{ // autogen a media path + Generate: true, + Monolithic: true, + }) cfg.Global.ServerName = "test" // use a distinct prefix else concurrent postgres/sqlite runs will clash since NATS will use // the file system event with InMemory=true :( @@ -49,7 +58,10 @@ func CreateBaseDendrite(t *testing.T, dbType test.DBType) (*base.BaseDendrite, f } return base.NewBaseDendrite(&cfg, "Test", base.DisableMetrics), close case test.DBTypeSQLite: - cfg.Defaults(true) // sets a sqlite db per component + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: false, // because we need a database per component + }) cfg.Global.ServerName = "test" // use a distinct prefix else concurrent postgres/sqlite runs will clash since NATS will use // the file system event with InMemory=true :( @@ -82,7 +94,10 @@ func CreateBaseDendrite(t *testing.T, dbType test.DBType) (*base.BaseDendrite, f func Base(cfg *config.Dendrite) (*base.BaseDendrite, nats.JetStreamContext, *nats.Conn) { if cfg == nil { cfg = &config.Dendrite{} - cfg.Defaults(true) + cfg.Defaults(config.DefaultOpts{ + Generate: true, + Monolithic: true, + }) } cfg.Global.JetStream.InMemory = true base := base.NewBaseDendrite(cfg, "Tests")