diff --git a/cli/server.go b/cli/server.go index aa0a010eb0aa4..7c9d467461bfd 100644 --- a/cli/server.go +++ b/cli/server.go @@ -897,31 +897,37 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. } // Manage notifications. - cfg := options.DeploymentValues.Notifications - metrics := notifications.NewMetrics(options.PrometheusRegistry) - helpers := templateHelpers(options) + var ( + cfg = options.DeploymentValues.Notifications + notificationsManager *notifications.Manager + ) - // The enqueuer is responsible for enqueueing notifications to the given store. - enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer"), quartz.NewReal()) - if err != nil { - return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err) - } - options.NotificationsEnqueuer = enqueuer + if cfg.Enabled { + metrics := notifications.NewMetrics(options.PrometheusRegistry) + helpers := templateHelpers(options) - // The notification manager is responsible for: - // - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications) - // - keeping the store updated with status updates - notificationsManager, err := notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager")) - if err != nil { - return xerrors.Errorf("failed to instantiate notification manager: %w", err) - } + // The enqueuer is responsible for enqueueing notifications to the given store. + enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer"), quartz.NewReal()) + if err != nil { + return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err) + } + options.NotificationsEnqueuer = enqueuer - // nolint:gocritic // We need to run the manager in a notifier context. - notificationsManager.Run(dbauthz.AsNotifier(ctx)) + // The notification manager is responsible for: + // - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications) + // - keeping the store updated with status updates + notificationsManager, err = notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager")) + if err != nil { + return xerrors.Errorf("failed to instantiate notification manager: %w", err) + } + + // nolint:gocritic // We need to run the manager in a notifier context. + notificationsManager.Run(dbauthz.AsNotifier(ctx)) - // Run report generator to distribute periodic reports. - notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal()) - defer notificationReportGenerator.Close() + // Run report generator to distribute periodic reports. + notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal()) + defer notificationReportGenerator.Close() + } // Since errCh only has one buffered slot, all routines // sending on it must be wrapped in a select/default to @@ -1098,17 +1104,19 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. // Cancel any remaining in-flight requests. shutdownConns() - // Stop the notification manager, which will cause any buffered updates to the store to be flushed. - // If the Stop() call times out, messages that were sent but not reflected as such in the store will have - // their leases expire after a period of time and will be re-queued for sending. - // See CODER_NOTIFICATIONS_LEASE_PERIOD. - cliui.Info(inv.Stdout, "Shutting down notifications manager..."+"\n") - err = shutdownWithTimeout(notificationsManager.Stop, 5*time.Second) - if err != nil { - cliui.Warnf(inv.Stderr, "Notifications manager shutdown took longer than 5s, "+ - "this may result in duplicate notifications being sent: %s\n", err) - } else { - cliui.Info(inv.Stdout, "Gracefully shut down notifications manager\n") + if notificationsManager != nil { + // Stop the notification manager, which will cause any buffered updates to the store to be flushed. + // If the Stop() call times out, messages that were sent but not reflected as such in the store will have + // their leases expire after a period of time and will be re-queued for sending. + // See CODER_NOTIFICATIONS_LEASE_PERIOD. + cliui.Info(inv.Stdout, "Shutting down notifications manager..."+"\n") + err = shutdownWithTimeout(notificationsManager.Stop, 5*time.Second) + if err != nil { + cliui.Warnf(inv.Stderr, "Notifications manager shutdown took longer than 5s, "+ + "this may result in duplicate notifications being sent: %s\n", err) + } else { + cliui.Info(inv.Stdout, "Gracefully shut down notifications manager\n") + } } // Shut down provisioners before waiting for WebSockets diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index 7e4088ccb6212..571299dbc6097 100644 --- a/cli/testdata/coder_server_--help.golden +++ b/cli/testdata/coder_server_--help.golden @@ -118,7 +118,7 @@ Configure how emails are sent. --email-hello string, $CODER_EMAIL_HELLO (default: localhost) The hostname identifying the SMTP server. - --email-smarthost host:port, $CODER_EMAIL_SMARTHOST (default: localhost:587) + --email-smarthost string, $CODER_EMAIL_SMARTHOST The intermediary SMTP host through which emails are sent. EMAIL / EMAIL AUTHENTICATION OPTIONS: @@ -392,6 +392,9 @@ Configure how notifications are processed and delivered. --notifications-dispatch-timeout duration, $CODER_NOTIFICATIONS_DISPATCH_TIMEOUT (default: 1m0s) How long to wait while a notification is being sent before giving up. + --notifications-enabled bool, $CODER_NOTIFICATIONS_ENABLED (default: true) + Controls if notifications are enabled. + --notifications-max-send-attempts int, $CODER_NOTIFICATIONS_MAX_SEND_ATTEMPTS (default: 5) The upper limit of attempts to send a notification. @@ -409,11 +412,11 @@ Configure how email notifications are sent. The sender's address to use. DEPRECATED: Use --email-from instead. - --notifications-email-hello string, $CODER_NOTIFICATIONS_EMAIL_HELLO + --notifications-email-hello string, $CODER_NOTIFICATIONS_EMAIL_HELLO (default: localhost) The hostname identifying the SMTP server. DEPRECATED: Use --email-hello instead. - --notifications-email-smarthost host:port, $CODER_NOTIFICATIONS_EMAIL_SMARTHOST + --notifications-email-smarthost string, $CODER_NOTIFICATIONS_EMAIL_SMARTHOST The intermediary SMTP host through which emails are sent. DEPRECATED: Use --email-smarthost instead. diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden index 38b2b68c24de1..63764c06449f0 100644 --- a/cli/testdata/server-config.yaml.golden +++ b/cli/testdata/server-config.yaml.golden @@ -518,53 +518,11 @@ userQuietHoursSchedule: # compatibility reasons, this will be removed in a future release. # (default: false, type: bool) allowWorkspaceRenames: false -# Configure how emails are sent. -email: - # The sender's address to use. - # (default: , type: string) - from: "" - # The intermediary SMTP host through which emails are sent. - # (default: localhost:587, type: host:port) - smarthost: localhost:587 - # The hostname identifying the SMTP server. - # (default: localhost, type: string) - hello: localhost - # Force a TLS connection to the configured SMTP smarthost. - # (default: false, type: bool) - forceTLS: false - # Configure SMTP authentication options. - emailAuth: - # Identity to use with PLAIN authentication. - # (default: , type: string) - identity: "" - # Username to use with PLAIN/LOGIN authentication. - # (default: , type: string) - username: "" - # File from which to load password for use with PLAIN/LOGIN authentication. - # (default: , type: string) - passwordFile: "" - # Configure TLS for your SMTP server target. - emailTLS: - # Enable STARTTLS to upgrade insecure SMTP connections using TLS. - # (default: , type: bool) - startTLS: false - # Server name to verify against the target certificate. - # (default: , type: string) - serverName: "" - # Skip verification of the target server's certificate (insecure). - # (default: , type: bool) - insecureSkipVerify: false - # CA certificate file to use. - # (default: , type: string) - caCertFile: "" - # Certificate file to use. - # (default: , type: string) - certFile: "" - # Certificate key file to use. - # (default: , type: string) - certKeyFile: "" # Configure how notifications are processed and delivered. notifications: + # Controls if notifications are enabled. + # (default: true, type: bool) + enabled: true # Which delivery method to use (available options: 'smtp', 'webhook'). # (default: smtp, type: string) method: smtp @@ -577,10 +535,10 @@ notifications: # (default: , type: string) from: "" # The intermediary SMTP host through which emails are sent. - # (default: , type: host:port) - smarthost: localhost:587 - # The hostname identifying the SMTP server. # (default: , type: string) + smarthost: "" + # The hostname identifying the SMTP server. + # (default: localhost, type: string) hello: localhost # Force a TLS connection to the configured SMTP smarthost. # (default: , type: bool) @@ -654,3 +612,48 @@ notifications: # How often to query the database for queued notifications. # (default: 15s, type: duration) fetchInterval: 15s +# Configure how emails are sent. +email: + # The sender's address to use. + # (default: , type: string) + from: "" + # The intermediary SMTP host through which emails are sent. + # (default: , type: string) + smarthost: "" + # The hostname identifying the SMTP server. + # (default: localhost, type: string) + hello: localhost + # Force a TLS connection to the configured SMTP smarthost. + # (default: false, type: bool) + forceTLS: false + # Configure SMTP authentication options. + emailAuth: + # Identity to use with PLAIN authentication. + # (default: , type: string) + identity: "" + # Username to use with PLAIN/LOGIN authentication. + # (default: , type: string) + username: "" + # File from which to load password for use with PLAIN/LOGIN authentication. + # (default: , type: string) + passwordFile: "" + # Configure TLS for your SMTP server target. + emailTLS: + # Enable STARTTLS to upgrade insecure SMTP connections using TLS. + # (default: , type: bool) + startTLS: false + # Server name to verify against the target certificate. + # (default: , type: string) + serverName: "" + # Skip verification of the target server's certificate (insecure). + # (default: , type: bool) + insecureSkipVerify: false + # CA certificate file to use. + # (default: , type: string) + caCertFile: "" + # Certificate file to use. + # (default: , type: string) + certFile: "" + # Certificate key file to use. + # (default: , type: string) + certKeyFile: "" diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 983abb61169c9..1955e41747e12 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -11383,6 +11383,9 @@ const docTemplate = `{ } ] }, + "enabled": { + "type": "boolean" + }, "fetch_interval": { "description": "How often to query the database for queued notifications.", "type": "integer" @@ -11471,11 +11474,7 @@ const docTemplate = `{ }, "smarthost": { "description": "The intermediary SMTP host through which emails are sent (host:port).", - "allOf": [ - { - "$ref": "#/definitions/serpent.HostPort" - } - ] + "type": "string" }, "tls": { "description": "TLS details.", diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 67cc92c71331d..f5e44b46eada7 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -10208,6 +10208,9 @@ } ] }, + "enabled": { + "type": "boolean" + }, "fetch_interval": { "description": "How often to query the database for queued notifications.", "type": "integer" @@ -10296,11 +10299,7 @@ }, "smarthost": { "description": "The intermediary SMTP host through which emails are sent (host:port).", - "allOf": [ - { - "$ref": "#/definitions/serpent.HostPort" - } - ] + "type": "string" }, "tls": { "description": "TLS details.", diff --git a/coderd/notifications/dispatch/smtp.go b/coderd/notifications/dispatch/smtp.go index dfb628b62eb86..d2dc7cdf20872 100644 --- a/coderd/notifications/dispatch/smtp.go +++ b/coderd/notifications/dispatch/smtp.go @@ -34,11 +34,10 @@ import ( ) var ( - ValidationNoFromAddressErr = xerrors.New("no 'from' address defined") - ValidationNoToAddressErr = xerrors.New("no 'to' address(es) defined") - ValidationNoSmarthostHostErr = xerrors.New("smarthost 'host' is not defined, or is invalid") - ValidationNoSmarthostPortErr = xerrors.New("smarthost 'port' is not defined, or is invalid") - ValidationNoHelloErr = xerrors.New("'hello' not defined") + ValidationNoFromAddressErr = xerrors.New("'from' address not defined") + ValidationNoToAddressErr = xerrors.New("'to' address(es) not defined") + ValidationNoSmarthostErr = xerrors.New("'smarthost' not defined") + ValidationNoHelloErr = xerrors.New("'hello' not defined") //go:embed smtp/html.gotmpl htmlTemplate string @@ -521,15 +520,14 @@ func (s *SMTPHandler) validateToAddrs(to string) ([]string, error) { // Does not allow overriding. // nolint:revive // documented. func (s *SMTPHandler) smarthost() (string, string, error) { - host := s.cfg.Smarthost.Host - port := s.cfg.Smarthost.Port - - // We don't validate the contents themselves; this will be done by the underlying SMTP library. - if host == "" { - return "", "", ValidationNoSmarthostHostErr + hostport := strings.TrimSpace(s.cfg.Smarthost.String()) + if hostport == "" { + return "", "", ValidationNoSmarthostErr } - if port == "" { - return "", "", ValidationNoSmarthostPortErr + + host, port, err := net.SplitHostPort(hostport) + if err != nil { + return "", "", xerrors.Errorf("split host port: %w", err) } return host, port, nil diff --git a/coderd/notifications/dispatch/smtp_test.go b/coderd/notifications/dispatch/smtp_test.go index c9a60b426ae70..b448dd2582e67 100644 --- a/coderd/notifications/dispatch/smtp_test.go +++ b/coderd/notifications/dispatch/smtp_test.go @@ -440,7 +440,7 @@ func TestSMTP(t *testing.T) { var hp serpent.HostPort require.NoError(t, hp.Set(listen.Addr().String())) - tc.cfg.Smarthost = hp + tc.cfg.Smarthost = serpent.String(hp.String()) handler := dispatch.NewSMTPHandler(tc.cfg, logger.Named("smtp")) diff --git a/coderd/notifications/notifications_test.go b/coderd/notifications/notifications_test.go index 763046bc20cb0..6ba8f614bd38d 100644 --- a/coderd/notifications/notifications_test.go +++ b/coderd/notifications/notifications_test.go @@ -155,7 +155,7 @@ func TestSMTPDispatch(t *testing.T) { cfg := defaultNotificationsConfig(method) cfg.SMTP = codersdk.NotificationsEmailConfig{ From: from, - Smarthost: serpent.HostPort{Host: "localhost", Port: fmt.Sprintf("%d", mockSMTPSrv.PortNumber())}, + Smarthost: serpent.String(fmt.Sprintf("localhost:%d", mockSMTPSrv.PortNumber())), Hello: "localhost", } handler := newDispatchInterceptor(dispatch.NewSMTPHandler(cfg.SMTP, logger.Named("smtp"))) @@ -1113,7 +1113,7 @@ func TestNotificationTemplates_Golden(t *testing.T) { var hp serpent.HostPort require.NoError(t, hp.Set(listen.Addr().String())) - smtpConfig.Smarthost = hp + smtpConfig.Smarthost = serpent.String(hp.String()) // Start mock SMTP server in the background. var wg sync.WaitGroup @@ -1524,7 +1524,7 @@ func TestCustomNotificationMethod(t *testing.T) { cfg.SMTP = codersdk.NotificationsEmailConfig{ From: "danny@coder.com", Hello: "localhost", - Smarthost: serpent.HostPort{Host: "localhost", Port: fmt.Sprintf("%d", mockSMTPSrv.PortNumber())}, + Smarthost: serpent.String(fmt.Sprintf("localhost:%d", mockSMTPSrv.PortNumber())), } cfg.Webhook = codersdk.NotificationsWebhookConfig{ Endpoint: *serpent.URLOf(endpoint), diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 0a97da7d3958f..835f0656ccec4 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -649,6 +649,8 @@ type HealthcheckConfig struct { } type NotificationsConfig struct { + Enabled serpent.Bool `json:"enabled" typescript:",notnull"` + // The upper limit of attempts to send a notification. MaxSendAttempts serpent.Int64 `json:"max_send_attempts" typescript:",notnull"` // The minimum time between retries. @@ -690,7 +692,7 @@ type NotificationsEmailConfig struct { // The sender's address. From serpent.String `json:"from" typescript:",notnull"` // The intermediary SMTP host through which emails are sent (host:port). - Smarthost serpent.HostPort `json:"smarthost" typescript:",notnull"` + Smarthost serpent.String `json:"smarthost" typescript:",notnull"` // The hostname identifying the SMTP server. Hello serpent.String `json:"hello" typescript:",notnull"` @@ -1028,7 +1030,6 @@ when required by your organization's security policy.`, Description: "The intermediary SMTP host through which emails are sent.", Flag: "email-smarthost", Env: "CODER_EMAIL_SMARTHOST", - Default: "localhost:587", // To pass validation. Value: &c.Notifications.SMTP.Smarthost, Group: &deploymentGroupEmail, YAML: "smarthost", @@ -2595,22 +2596,17 @@ Write out the current server config as YAML to stdout.`, YAML: "thresholdDatabase", Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"), }, - // Email options - emailFrom, - emailSmarthost, - emailHello, - emailForceTLS, - emailAuthIdentity, - emailAuthUsername, - emailAuthPassword, - emailAuthPasswordFile, - emailTLSStartTLS, - emailTLSServerName, - emailTLSSkipCertVerify, - emailTLSCertAuthorityFile, - emailTLSCertFile, - emailTLSCertKeyFile, // Notifications Options + { + Name: "Notifications: Enabled", + Description: "Controls if notifications are enabled.", + Flag: "notifications-enabled", + Env: "CODER_NOTIFICATIONS_ENABLED", + Default: "true", + Value: &c.Notifications.Enabled, + Group: &deploymentGroupNotifications, + YAML: "enabled", + }, { Name: "Notifications: Method", Description: "Which delivery method to use (available options: 'smtp', 'webhook').", @@ -2657,6 +2653,7 @@ Write out the current server config as YAML to stdout.`, Description: "The hostname identifying the SMTP server.", Flag: "notifications-email-hello", Env: "CODER_NOTIFICATIONS_EMAIL_HELLO", + Default: "localhost", Value: &c.Notifications.SMTP.Hello, Group: &deploymentGroupNotificationsEmail, YAML: "hello", @@ -2871,6 +2868,21 @@ Write out the current server config as YAML to stdout.`, Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"), Hidden: true, // Hidden because most operators should not need to modify this. }, + // Email options + emailFrom, + emailSmarthost, + emailHello, + emailForceTLS, + emailAuthIdentity, + emailAuthUsername, + emailAuthPassword, + emailAuthPasswordFile, + emailTLSStartTLS, + emailTLSServerName, + emailTLSSkipCertVerify, + emailTLSCertAuthorityFile, + emailTLSCertFile, + emailTLSCertKeyFile, } return opts diff --git a/codersdk/deployment_test.go b/codersdk/deployment_test.go index 61474a3b77ea1..4878c6ac691b7 100644 --- a/codersdk/deployment_test.go +++ b/codersdk/deployment_test.go @@ -568,3 +568,115 @@ func TestPremiumSuperSet(t *testing.T) { require.NotContains(t, enterprise.Features(), "", "enterprise should not contain empty string") require.NotContains(t, premium.Features(), "", "premium should not contain empty string") } + +func TestEmailValuesTakeCorrectPrecedent(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + envs []serpent.EnvVar + oldEnv string + newEnv string + expectedValue string + }{ + { + name: "CODER_NOTIFICATIONS_EMAIL_SMARTHOST is not discarded", + envs: []serpent.EnvVar{ + { + Name: "CODER_NOTIFICATIONS_EMAIL_SMARTHOST", + Value: "localhost:999", + }, + }, + oldEnv: "CODER_NOTIFICATIONS_EMAIL_SMARTHOST", + newEnv: "CODER_EMAIL_SMARTHOST", + expectedValue: "localhost:999", + }, + { + name: "CODER_EMAIL_SMARTHOST is not discarded", + envs: []serpent.EnvVar{ + { + Name: "CODER_EMAIL_SMARTHOST", + Value: "localhost:999", + }, + }, + oldEnv: "CODER_NOTIFICATIONS_EMAIL_SMARTHOST", + newEnv: "CODER_EMAIL_SMARTHOST", + expectedValue: "localhost:999", + }, + { + name: "CODER_EMAIL_SMARTHOST is prioritized", + envs: []serpent.EnvVar{ + { + Name: "CODER_NOTIFICATIONS_EMAIL_SMARTHOST", + Value: "localhost:999", + }, + { + Name: "CODER_EMAIL_SMARTHOST", + Value: "localhost:1000", + }, + }, + oldEnv: "CODER_NOTIFICATIONS_EMAIL_SMARTHOST", + newEnv: "CODER_EMAIL_SMARTHOST", + expectedValue: "localhost:1000", + }, + { + name: "CODER_NOTIFICATIONS_EMAIL_HELLO is not discarded", + envs: []serpent.EnvVar{ + { + Name: "CODER_NOTIFICATIONS_EMAIL_HELLO", + Value: "not-localhost", + }, + }, + oldEnv: "CODER_NOTIFICATIONS_EMAIL_HELLO", + newEnv: "CODER_EMAIL_HELLO", + expectedValue: "not-localhost", + }, + { + name: "CODER_EMAIL_HELLO is not discarded", + envs: []serpent.EnvVar{ + { + Name: "CODER_EMAIL_HELLO", + Value: "not-localhost", + }, + }, + oldEnv: "CODER_NOTIFICATIONS_EMAIL_HELLO", + newEnv: "CODER_EMAIL_HELLO", + expectedValue: "not-localhost", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + dv := codersdk.DeploymentValues{} + opts := dv.Options() + + err := opts.ParseEnv(tt.envs) + require.NoError(t, err) + + err = opts.SetDefaults() + require.NoError(t, err) + + var oldEnvValue string + var newEnvValue string + + for _, opt := range opts { + switch { + case opt.Env == tt.oldEnv: + oldEnvValue = opt.Value.String() + case opt.Env == tt.newEnv: + newEnvValue = opt.Value.String() + } + + if oldEnvValue != "" && newEnvValue != "" { + break + } + } + + require.Equal(t, tt.expectedValue, oldEnvValue) + require.Equal(t, tt.expectedValue, newEnvValue) + }) + } +} diff --git a/docs/reference/api/general.md b/docs/reference/api/general.md index b6452545842f7..227e99d4d3964 100644 --- a/docs/reference/api/general.md +++ b/docs/reference/api/general.md @@ -266,10 +266,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ "force_tls": true, "from": "string", "hello": "string", - "smarthost": { - "host": "string", - "port": "string" - }, + "smarthost": "string", "tls": { "ca_file": "string", "cert_file": "string", @@ -279,6 +276,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ "start_tls": true } }, + "enabled": true, "fetch_interval": 0, "lease_count": 0, "lease_period": 0, diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index fe8db822aafb5..63b8ca7a314c2 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -1884,10 +1884,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "force_tls": true, "from": "string", "hello": "string", - "smarthost": { - "host": "string", - "port": "string" - }, + "smarthost": "string", "tls": { "ca_file": "string", "cert_file": "string", @@ -1897,6 +1894,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "start_tls": true } }, + "enabled": true, "fetch_interval": 0, "lease_count": 0, "lease_period": 0, @@ -2311,10 +2309,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "force_tls": true, "from": "string", "hello": "string", - "smarthost": { - "host": "string", - "port": "string" - }, + "smarthost": "string", "tls": { "ca_file": "string", "cert_file": "string", @@ -2324,6 +2319,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "start_tls": true } }, + "enabled": true, "fetch_interval": 0, "lease_count": 0, "lease_period": 0, @@ -3417,10 +3413,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "force_tls": true, "from": "string", "hello": "string", - "smarthost": { - "host": "string", - "port": "string" - }, + "smarthost": "string", "tls": { "ca_file": "string", "cert_file": "string", @@ -3430,6 +3423,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "start_tls": true } }, + "enabled": true, "fetch_interval": 0, "lease_count": 0, "lease_period": 0, @@ -3462,6 +3456,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o | ------------------- | -------------------------------------------------------------------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dispatch_timeout` | integer | false | | How long to wait while a notification is being sent before giving up. | | `email` | [codersdk.NotificationsEmailConfig](#codersdknotificationsemailconfig) | false | | Email settings. | +| `enabled` | boolean | false | | | | `fetch_interval` | integer | false | | How often to query the database for queued notifications. | | `lease_count` | integer | false | | How many notifications a notifier should lease per fetch interval. | | `lease_period` | integer | false | | How long a notifier should lease a message. This is effectively how long a notification is 'owned' by a notifier, and once this period expires it will be available for lease by another notifier. Leasing is important in order for multiple running notifiers to not pick the same messages to deliver concurrently. This lease period will only expire if a notifier shuts down ungracefully; a dispatch of the notification releases the lease. | @@ -3505,10 +3500,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "force_tls": true, "from": "string", "hello": "string", - "smarthost": { - "host": "string", - "port": "string" - }, + "smarthost": "string", "tls": { "ca_file": "string", "cert_file": "string", @@ -3528,7 +3520,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o | `force_tls` | boolean | false | | Force tls causes a TLS connection to be attempted. | | `from` | string | false | | The sender's address. | | `hello` | string | false | | The hostname identifying the SMTP server. | -| `smarthost` | [serpent.HostPort](#serpenthostport) | false | | The intermediary SMTP host through which emails are sent (host:port). | +| `smarthost` | string | false | | The intermediary SMTP host through which emails are sent (host:port). | | `tls` | [codersdk.NotificationsEmailTLSConfig](#codersdknotificationsemailtlsconfig) | false | | Tls details. | ## codersdk.NotificationsEmailTLSConfig diff --git a/docs/reference/cli/server.md b/docs/reference/cli/server.md index 3b3d2376c9aab..d655547e63faa 100644 --- a/docs/reference/cli/server.md +++ b/docs/reference/cli/server.md @@ -1217,147 +1217,16 @@ Refresh interval for healthchecks. The threshold for the database health check. If the median latency of the database exceeds this threshold over 5 attempts, the database is considered unhealthy. The default value is 15ms. -### --email-from - -| | | -| ----------- | ------------------------------ | -| Type | string | -| Environment | $CODER_EMAIL_FROM | -| YAML | email.from | - -The sender's address to use. - -### --email-smarthost - -| | | -| ----------- | ----------------------------------- | -| Type | host:port | -| Environment | $CODER_EMAIL_SMARTHOST | -| YAML | email.smarthost | -| Default | localhost:587 | - -The intermediary SMTP host through which emails are sent. - -### --email-hello - -| | | -| ----------- | ------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_HELLO | -| YAML | email.hello | -| Default | localhost | - -The hostname identifying the SMTP server. - -### --email-force-tls - -| | | -| ----------- | ----------------------------------- | -| Type | bool | -| Environment | $CODER_EMAIL_FORCE_TLS | -| YAML | email.forceTLS | -| Default | false | - -Force a TLS connection to the configured SMTP smarthost. - -### --email-auth-identity - -| | | -| ----------- | --------------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_AUTH_IDENTITY | -| YAML | email.emailAuth.identity | - -Identity to use with PLAIN authentication. - -### --email-auth-username - -| | | -| ----------- | --------------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_AUTH_USERNAME | -| YAML | email.emailAuth.username | - -Username to use with PLAIN/LOGIN authentication. - -### --email-auth-password - -| | | -| ----------- | --------------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_AUTH_PASSWORD | - -Password to use with PLAIN/LOGIN authentication. - -### --email-auth-password-file - -| | | -| ----------- | -------------------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_AUTH_PASSWORD_FILE | -| YAML | email.emailAuth.passwordFile | - -File from which to load password for use with PLAIN/LOGIN authentication. - -### --email-tls-starttls - -| | | -| ----------- | -------------------------------------- | -| Type | bool | -| Environment | $CODER_EMAIL_TLS_STARTTLS | -| YAML | email.emailTLS.startTLS | - -Enable STARTTLS to upgrade insecure SMTP connections using TLS. - -### --email-tls-server-name - -| | | -| ----------- | ---------------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_TLS_SERVERNAME | -| YAML | email.emailTLS.serverName | - -Server name to verify against the target certificate. - -### --email-tls-skip-verify - -| | | -| ----------- | ---------------------------------------------- | -| Type | bool | -| Environment | $CODER_EMAIL_TLS_SKIPVERIFY | -| YAML | email.emailTLS.insecureSkipVerify | - -Skip verification of the target server's certificate (insecure). - -### --email-tls-ca-cert-file - -| | | -| ----------- | ---------------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_TLS_CACERTFILE | -| YAML | email.emailTLS.caCertFile | - -CA certificate file to use. - -### --email-tls-cert-file - -| | | -| ----------- | -------------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_TLS_CERTFILE | -| YAML | email.emailTLS.certFile | - -Certificate file to use. - -### --email-tls-cert-key-file +### --notifications-enabled | | | | ----------- | ----------------------------------------- | -| Type | string | -| Environment | $CODER_EMAIL_TLS_CERTKEYFILE | -| YAML | email.emailTLS.certKeyFile | +| Type | bool | +| Environment | $CODER_NOTIFICATIONS_ENABLED | +| YAML | notifications.enabled | +| Default | true | -Certificate key file to use. +Controls if notifications are enabled. ### --notifications-method @@ -1395,7 +1264,7 @@ The sender's address to use. | | | | ----------- | ------------------------------------------------- | -| Type | host:port | +| Type | string | | Environment | $CODER_NOTIFICATIONS_EMAIL_SMARTHOST | | YAML | notifications.email.smarthost | @@ -1408,6 +1277,7 @@ The intermediary SMTP host through which emails are sent. | Type | string | | Environment | $CODER_NOTIFICATIONS_EMAIL_HELLO | | YAML | notifications.email.hello | +| Default | localhost | The hostname identifying the SMTP server. @@ -1540,3 +1410,144 @@ The endpoint to which to send webhooks. | Default | 5 | The upper limit of attempts to send a notification. + +### --email-from + +| | | +| ----------- | ------------------------------ | +| Type | string | +| Environment | $CODER_EMAIL_FROM | +| YAML | email.from | + +The sender's address to use. + +### --email-smarthost + +| | | +| ----------- | ----------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_SMARTHOST | +| YAML | email.smarthost | + +The intermediary SMTP host through which emails are sent. + +### --email-hello + +| | | +| ----------- | ------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_HELLO | +| YAML | email.hello | +| Default | localhost | + +The hostname identifying the SMTP server. + +### --email-force-tls + +| | | +| ----------- | ----------------------------------- | +| Type | bool | +| Environment | $CODER_EMAIL_FORCE_TLS | +| YAML | email.forceTLS | +| Default | false | + +Force a TLS connection to the configured SMTP smarthost. + +### --email-auth-identity + +| | | +| ----------- | --------------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_AUTH_IDENTITY | +| YAML | email.emailAuth.identity | + +Identity to use with PLAIN authentication. + +### --email-auth-username + +| | | +| ----------- | --------------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_AUTH_USERNAME | +| YAML | email.emailAuth.username | + +Username to use with PLAIN/LOGIN authentication. + +### --email-auth-password + +| | | +| ----------- | --------------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_AUTH_PASSWORD | + +Password to use with PLAIN/LOGIN authentication. + +### --email-auth-password-file + +| | | +| ----------- | -------------------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_AUTH_PASSWORD_FILE | +| YAML | email.emailAuth.passwordFile | + +File from which to load password for use with PLAIN/LOGIN authentication. + +### --email-tls-starttls + +| | | +| ----------- | -------------------------------------- | +| Type | bool | +| Environment | $CODER_EMAIL_TLS_STARTTLS | +| YAML | email.emailTLS.startTLS | + +Enable STARTTLS to upgrade insecure SMTP connections using TLS. + +### --email-tls-server-name + +| | | +| ----------- | ---------------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_TLS_SERVERNAME | +| YAML | email.emailTLS.serverName | + +Server name to verify against the target certificate. + +### --email-tls-skip-verify + +| | | +| ----------- | ---------------------------------------------- | +| Type | bool | +| Environment | $CODER_EMAIL_TLS_SKIPVERIFY | +| YAML | email.emailTLS.insecureSkipVerify | + +Skip verification of the target server's certificate (insecure). + +### --email-tls-ca-cert-file + +| | | +| ----------- | ---------------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_TLS_CACERTFILE | +| YAML | email.emailTLS.caCertFile | + +CA certificate file to use. + +### --email-tls-cert-file + +| | | +| ----------- | -------------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_TLS_CERTFILE | +| YAML | email.emailTLS.certFile | + +Certificate file to use. + +### --email-tls-cert-key-file + +| | | +| ----------- | ----------------------------------------- | +| Type | string | +| Environment | $CODER_EMAIL_TLS_CERTKEYFILE | +| YAML | email.emailTLS.certKeyFile | + +Certificate key file to use. diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden index aaa4725c65181..be4a86e32d323 100644 --- a/enterprise/cli/testdata/coder_server_--help.golden +++ b/enterprise/cli/testdata/coder_server_--help.golden @@ -119,7 +119,7 @@ Configure how emails are sent. --email-hello string, $CODER_EMAIL_HELLO (default: localhost) The hostname identifying the SMTP server. - --email-smarthost host:port, $CODER_EMAIL_SMARTHOST (default: localhost:587) + --email-smarthost string, $CODER_EMAIL_SMARTHOST The intermediary SMTP host through which emails are sent. EMAIL / EMAIL AUTHENTICATION OPTIONS: @@ -393,6 +393,9 @@ Configure how notifications are processed and delivered. --notifications-dispatch-timeout duration, $CODER_NOTIFICATIONS_DISPATCH_TIMEOUT (default: 1m0s) How long to wait while a notification is being sent before giving up. + --notifications-enabled bool, $CODER_NOTIFICATIONS_ENABLED (default: true) + Controls if notifications are enabled. + --notifications-max-send-attempts int, $CODER_NOTIFICATIONS_MAX_SEND_ATTEMPTS (default: 5) The upper limit of attempts to send a notification. @@ -410,11 +413,11 @@ Configure how email notifications are sent. The sender's address to use. DEPRECATED: Use --email-from instead. - --notifications-email-hello string, $CODER_NOTIFICATIONS_EMAIL_HELLO + --notifications-email-hello string, $CODER_NOTIFICATIONS_EMAIL_HELLO (default: localhost) The hostname identifying the SMTP server. DEPRECATED: Use --email-hello instead. - --notifications-email-smarthost host:port, $CODER_NOTIFICATIONS_EMAIL_SMARTHOST + --notifications-email-smarthost string, $CODER_NOTIFICATIONS_EMAIL_SMARTHOST The intermediary SMTP host through which emails are sent. DEPRECATED: Use --email-smarthost instead. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index bd00dbda353c3..36cb7f389cae5 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -800,6 +800,7 @@ export interface NotificationTemplate { // From codersdk/deployment.go export interface NotificationsConfig { + readonly enabled: boolean; readonly max_send_attempts: number; readonly retry_interval: number; readonly sync_interval: number;