Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat!: allow disabling notifications#15509

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
DanielleMaywood merged 24 commits intomainfromdm-fix-defaults-notifications
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
24 commits
Select commitHold shift + click to select a range
5c36c93
fix: remove defaults for CODER_EMAIL_ options
DanielleMaywoodNov 12, 2024
196f538
fix: failing tests
DanielleMaywoodNov 12, 2024
b670009
fix: tests (again)
DanielleMaywoodNov 12, 2024
19398cc
fix: run 'make gen'
DanielleMaywoodNov 12, 2024
4175bc8
fix: consistency
DanielleMaywoodNov 13, 2024
66d1a69
nit: trim smarthost
DanielleMaywoodNov 13, 2024
4689e5b
nit: re-add default for CODER_EMAIL_HELLO
DanielleMaywoodNov 13, 2024
01d4957
fix: run 'make {update-golden-files,gen}'
DanielleMaywoodNov 13, 2024
27fa5bf
fix: run 'make fmt'
DanielleMaywoodNov 13, 2024
6ca7844
feat: allow disabling notifications entirely
DanielleMaywoodNov 13, 2024
fb54e45
Merge branch 'main' into dm-fix-defaults-notifications
DanielleMaywoodNov 14, 2024
d5aff28
chore: re-add default for smarthost
DanielleMaywoodNov 14, 2024
01cb999
fix: remove default for deprecated option
DanielleMaywoodNov 14, 2024
c513113
chore: revert change
DanielleMaywoodNov 14, 2024
a8b5a61
chore: remove unrelated test changes
DanielleMaywoodNov 14, 2024
1711e68
revert: more changes
DanielleMaywoodNov 14, 2024
2e03ed1
chore: simplify description
DanielleMaywoodNov 14, 2024
28ec1b7
Merge branch 'main' into dm-fix-defaults-notifications
DanielleMaywoodNov 14, 2024
7ba3a6c
chore: make {gen,update-golden-files}
DanielleMaywoodNov 14, 2024
4a72e4f
chore: rename cfg to notificationsCfg
DanielleMaywoodNov 14, 2024
9c02842
chore: drop enabled flag
DanielleMaywoodNov 18, 2024
dd527f9
fix: invalid test
DanielleMaywoodNov 18, 2024
77d1803
chore: improve info message and add to docs
DanielleMaywoodNov 19, 2024
5fd03b3
test: notifications.Enabled()
DanielleMaywoodNov 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 42 additions & 32 deletionscli/server.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -897,31 +897,39 @@ 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 (
notificationsCfg = 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 notificationsCfg.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(notificationsCfg, 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

// 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(notificationsCfg, 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))
// 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()
} else {
cliui.Info(inv.Stdout, "Notifications are currently disabled as there are no configured delivery methods. See https://coder.com/docs/admin/monitoring/notifications#delivery-methods for more details.")
}

// Since errCh only has one buffered slot, all routines
// sending on it must be wrapped in a select/default to
Expand DownExpand Up@@ -1098,17 +1106,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
Expand Down
4 changes: 2 additions & 2 deletionscli/testdata/coder_server_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,7 +118,7 @@ Configure how emails are sent.
--email-hello string, $CODER_EMAIL_HELLO (default: localhost)
The hostname identifying the SMTP server.

--email-smarthosthost:port, $CODER_EMAIL_SMARTHOST (default: localhost:587)
--email-smarthoststring, $CODER_EMAIL_SMARTHOST
The intermediary SMTP host through which emails are sent.

EMAIL / EMAIL AUTHENTICATION OPTIONS:
Expand DownExpand Up@@ -413,7 +413,7 @@ Configure how email notifications are sent.
The hostname identifying the SMTP server.
DEPRECATED: Use --email-hello instead.

--notifications-email-smarthosthost:port, $CODER_NOTIFICATIONS_EMAIL_SMARTHOST
--notifications-email-smarthoststring, $CODER_NOTIFICATIONS_EMAIL_SMARTHOST
The intermediary SMTP host through which emails are sent.
DEPRECATED: Use --email-smarthost instead.

Expand Down
8 changes: 4 additions & 4 deletionscli/testdata/server-config.yaml.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -524,8 +524,8 @@ email:
# (default: <unset>, type: string)
from: ""
# The intermediary SMTP host through which emails are sent.
# (default:localhost:587, type:host:port)
smarthost:localhost:587
# (default:<unset>, type:string)
smarthost:""
# The hostname identifying the SMTP server.
# (default: localhost, type: string)
hello: localhost
Expand DownExpand Up@@ -577,8 +577,8 @@ notifications:
# (default: <unset>, type: string)
from: ""
# The intermediary SMTP host through which emails are sent.
# (default: <unset>, type:host:port)
smarthost:localhost:587
# (default: <unset>, type:string)
smarthost:""
# The hostname identifying the SMTP server.
# (default: <unset>, type: string)
hello: localhost
Expand Down
6 changes: 1 addition & 5 deletionscoderd/apidoc/docs.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

6 changes: 1 addition & 5 deletionscoderd/apidoc/swagger.json
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

24 changes: 11 additions & 13 deletionscoderd/notifications/dispatch/smtp.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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' address not defined")
ValidationNoHelloErr = xerrors.New("'hello' not defined")

//go:embed smtp/html.gotmpl
htmlTemplate string
Expand DownExpand Up@@ -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
smarthost := strings.TrimSpace(string(s.cfg.Smarthost))
if smarthost == "" {
return "", "", ValidationNoSmarthostErr
}
if port == "" {
return "", "", ValidationNoSmarthostPortErr

host, port, err := net.SplitHostPort(string(s.cfg.Smarthost))
if err != nil {
return "", "", xerrors.Errorf("split host port: %w", err)
}

return host, port, nil
Expand Down
2 changes: 1 addition & 1 deletioncoderd/notifications/dispatch/smtp_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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"))

Expand Down
6 changes: 3 additions & 3 deletionscoderd/notifications/notifications_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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")))
Expand DownExpand Up@@ -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
Expand DownExpand Up@@ -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),
Expand Down
7 changes: 5 additions & 2 deletionscodersdk/deployment.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -686,11 +686,15 @@ type NotificationsConfig struct {
Webhook NotificationsWebhookConfig `json:"webhook" typescript:",notnull"`
}

func (n *NotificationsConfig) Enabled() bool {
return n.SMTP.Smarthost != "" || n.Webhook.Endpoint != serpent.URL{}
}

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"`

Expand DownExpand Up@@ -1028,7 +1032,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",
Expand Down
66 changes: 66 additions & 0 deletionscodersdk/deployment_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -568,3 +568,69 @@ 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 TestNotificationsCanBeDisabled(t *testing.T) {
t.Parallel()

tests := []struct {
name string
expectNotificationsEnabled bool
environment []serpent.EnvVar
}{
{
name: "NoDeliveryMethodSet",
environment: []serpent.EnvVar{},
expectNotificationsEnabled: false,
},
{
name: "SMTP_DeliveryMethodSet",
environment: []serpent.EnvVar{
{
Name: "CODER_EMAIL_SMARTHOST",
Value: "localhost:587",
},
},
expectNotificationsEnabled: true,
},
{
name: "Webhook_DeliveryMethodSet",
environment: []serpent.EnvVar{
{
Name: "CODER_NOTIFICATIONS_WEBHOOK_ENDPOINT",
Value: "https://example.com/webhook",
},
},
expectNotificationsEnabled: true,
},
{
name: "WebhookAndSMTP_DeliveryMethodSet",
environment: []serpent.EnvVar{
{
Name: "CODER_NOTIFICATIONS_WEBHOOK_ENDPOINT",
Value: "https://example.com/webhook",
},
{
Name: "CODER_EMAIL_SMARTHOST",
Value: "localhost:587",
},
},
expectNotificationsEnabled: true,
},
}

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.environment)
require.NoError(t, err)

require.Equal(t, tt.expectNotificationsEnabled, dv.Notifications.Enabled())
})
}
}
13 changes: 7 additions & 6 deletionsdocs/admin/monitoring/notifications/index.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,8 @@ flags.
Notifications can currently be delivered by either SMTP or webhook. Each message
can only be delivered to one method, and this method is configured globally with
[`CODER_NOTIFICATIONS_METHOD`](../../../reference/cli/server.md#--notifications-method)
(default: `smtp`).
(default: `smtp`). When there are no delivery methods configured, notifications
will be disabled.

Premium customers can configure which method to use for each of the supported
[Events](#workspace-events); see the
Expand All@@ -89,11 +90,11 @@ existing one.

**Server Settings:**

| Required | CLI | Env | Type| Description | Default |
| :------: | ------------------- | ----------------------- | ----------- | ----------------------------------------- |------------- |
| ✔️ | `--email-from` | `CODER_EMAIL_FROM` | `string`| The sender's address to use. | |
| ✔️ | `--email-smarthost` | `CODER_EMAIL_SMARTHOST` | `host:port` | The SMTP relay to send messagesthrough. | localhost:587 |
| ✔️ | `--email-hello` | `CODER_EMAIL_HELLO` | `string`| The hostname identifying the SMTP server. | localhost |
| Required | CLI | Env | Type | Description | Default |
| :------: | ------------------- | ----------------------- | -------- | ----------------------------------------- | --------- |
| ✔️ | `--email-from` | `CODER_EMAIL_FROM` | `string` | The sender's address to use. | |
| ✔️ | `--email-smarthost` | `CODER_EMAIL_SMARTHOST` | `string` | The SMTP relay to send messages |
| ✔️ | `--email-hello` | `CODER_EMAIL_HELLO` | `string` | The hostname identifying the SMTP server. | localhost |

**Authentication Settings:**

Expand Down
5 changes: 1 addition & 4 deletionsdocs/reference/api/general.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp