diff --git a/AGENTS.md b/AGENTS.md index 8bc3d18882..91529f8950 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -113,7 +113,7 @@ Do not hand‑edit generated files under `api/v2/models`, `api/v2/restapi`, `api ## When adding or modifying a notifier - Each integration lives in its own package under `notify//`. -- Add config in `config/notifiers.go` (struct, validation, defaults) and wire it into `config/config.go` receivers. +- Add config in `notify//config.go` (struct, validation, defaults) and wire it into `config/config.go` receivers. - Register the notifier in `cmd/alertmanager/main.go` where receivers are built. - Add unit tests in the notifier package; reuse helpers from `notify/test/`. - Update `template/default.tmpl` only if you are introducing new default templates. diff --git a/config/common/hostport.go b/config/common/hostport.go new file mode 100644 index 0000000000..3c036e9e52 --- /dev/null +++ b/config/common/hostport.go @@ -0,0 +1,87 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +import ( + "encoding/json" + "fmt" + "net" +) + +// HostPort represents a "host:port" network address. +type HostPort struct { + Host string + Port string +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface for HostPort. +func (hp *HostPort) UnmarshalYAML(unmarshal func(any) error) error { + var ( + s string + err error + ) + if err = unmarshal(&s); err != nil { + return err + } + if s == "" { + return nil + } + hp.Host, hp.Port, err = net.SplitHostPort(s) + if err != nil { + return err + } + if hp.Port == "" { + return fmt.Errorf("address %q: port cannot be empty", s) + } + return nil +} + +// UnmarshalJSON implements the json.Unmarshaler interface for HostPort. +func (hp *HostPort) UnmarshalJSON(data []byte) error { + var ( + s string + err error + ) + if err = json.Unmarshal(data, &s); err != nil { + return err + } + if s == "" { + return nil + } + hp.Host, hp.Port, err = net.SplitHostPort(s) + if err != nil { + return err + } + if hp.Port == "" { + return fmt.Errorf("address %q: port cannot be empty", s) + } + return nil +} + +// MarshalYAML implements the yaml.Marshaler interface for HostPort. +func (hp HostPort) MarshalYAML() (any, error) { + return hp.String(), nil +} + +// MarshalJSON implements the json.Marshaler interface for HostPort. +func (hp HostPort) MarshalJSON() ([]byte, error) { + return json.Marshal(hp.String()) +} + +func (hp HostPort) String() string { + if hp.Host == "" && hp.Port == "" { + return "" + } + return net.JoinHostPort(hp.Host, hp.Port) +} diff --git a/config/common/hostport_test.go b/config/common/hostport_test.go new file mode 100644 index 0000000000..c3dd58a2ab --- /dev/null +++ b/config/common/hostport_test.go @@ -0,0 +1,89 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" +) + +func TestUnmarshalHostPort(t *testing.T) { + for _, tc := range []struct { + in string + + exp HostPort + jsonOut string + yamlOut string + err bool + }{ + { + in: `""`, + exp: HostPort{}, + yamlOut: `"" +`, + jsonOut: `""`, + }, + { + in: `"localhost:25"`, + exp: HostPort{Host: "localhost", Port: "25"}, + yamlOut: `localhost:25 +`, + jsonOut: `"localhost:25"`, + }, + { + in: `":25"`, + exp: HostPort{Host: "", Port: "25"}, + yamlOut: `:25 +`, + jsonOut: `":25"`, + }, + { + in: `"localhost"`, + err: true, + }, + { + in: `"localhost:"`, + err: true, + }, + { + in: `"[fd12:3456:789a::1]:25"`, + exp: HostPort{Host: "fd12:3456:789a::1", Port: "25"}, + yamlOut: `'[fd12:3456:789a::1]:25' +`, + jsonOut: `"[fd12:3456:789a::1]:25"`, + }, + } { + t.Run(tc.in, func(t *testing.T) { + hp := HostPort{} + err := yaml.Unmarshal([]byte(tc.in), &hp) + if tc.err { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tc.exp, hp) + + b, err := yaml.Marshal(&hp) + require.NoError(t, err) + require.Equal(t, tc.yamlOut, string(b)) + + b, err = json.Marshal(&hp) + require.NoError(t, err) + require.Equal(t, tc.jsonOut, string(b)) + }) + } +} diff --git a/config/config.go b/config/config.go index 45052ba819..a66ea7ec17 100644 --- a/config/config.go +++ b/config/config.go @@ -18,7 +18,6 @@ import ( "encoding/json" "errors" "fmt" - "net" "os" "path/filepath" "strings" @@ -33,6 +32,7 @@ import ( "github.com/prometheus/alertmanager/eventrecorder" "github.com/prometheus/alertmanager/matcher/compat" "github.com/prometheus/alertmanager/notify/discord" + "github.com/prometheus/alertmanager/notify/email" "github.com/prometheus/alertmanager/notify/incidentio" "github.com/prometheus/alertmanager/notify/jira" "github.com/prometheus/alertmanager/notify/mattermost" @@ -773,73 +773,6 @@ func DefaultGlobalConfig() GlobalConfig { } } -// HostPort represents a "host:port" network address. -type HostPort struct { - Host string - Port string -} - -// UnmarshalYAML implements the yaml.Unmarshaler interface for HostPort. -func (hp *HostPort) UnmarshalYAML(unmarshal func(any) error) error { - var ( - s string - err error - ) - if err = unmarshal(&s); err != nil { - return err - } - if s == "" { - return nil - } - hp.Host, hp.Port, err = net.SplitHostPort(s) - if err != nil { - return err - } - if hp.Port == "" { - return fmt.Errorf("address %q: port cannot be empty", s) - } - return nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface for HostPort. -func (hp *HostPort) UnmarshalJSON(data []byte) error { - var ( - s string - err error - ) - if err = json.Unmarshal(data, &s); err != nil { - return err - } - if s == "" { - return nil - } - hp.Host, hp.Port, err = net.SplitHostPort(s) - if err != nil { - return err - } - if hp.Port == "" { - return fmt.Errorf("address %q: port cannot be empty", s) - } - return nil -} - -// MarshalYAML implements the yaml.Marshaler interface for HostPort. -func (hp HostPort) MarshalYAML() (any, error) { - return hp.String(), nil -} - -// MarshalJSON implements the json.Marshaler interface for HostPort. -func (hp HostPort) MarshalJSON() ([]byte, error) { - return json.Marshal(hp.String()) -} - -func (hp HostPort) String() string { - if hp.Host == "" && hp.Port == "" { - return "" - } - return net.JoinHostPort(hp.Host, hp.Port) -} - // GlobalConfig defines configuration parameters that are valid globally // unless overwritten. type GlobalConfig struct { @@ -852,7 +785,7 @@ type GlobalConfig struct { JiraAPIURL *amcommoncfg.URL `yaml:"jira_api_url,omitempty" json:"jira_api_url,omitempty"` SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"` SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"` - SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"` + SMTPSmarthost amcommoncfg.HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"` SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"` SMTPAuthPassword commoncfg.Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"` SMTPAuthPasswordFile string `yaml:"smtp_auth_password_file,omitempty" json:"smtp_auth_password_file,omitempty"` @@ -992,7 +925,7 @@ type Receiver struct { Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"` DiscordConfigs []*discord.DiscordConfig `yaml:"discord_configs,omitempty" json:"discord_configs,omitempty"` - EmailConfigs []*EmailConfig `yaml:"email_configs,omitempty" json:"email_configs,omitempty"` + EmailConfigs []*email.EmailConfig `yaml:"email_configs,omitempty" json:"email_configs,omitempty"` IncidentioConfigs []*incidentio.IncidentioConfig `yaml:"incidentio_configs,omitempty" json:"incidentio_configs,omitempty"` PagerdutyConfigs []*pagerduty.PagerdutyConfig `yaml:"pagerduty_configs,omitempty" json:"pagerduty_configs,omitempty"` SlackConfigs []*slack.SlackConfig `yaml:"slack_configs,omitempty" json:"slack_configs,omitempty"` diff --git a/config/config_test.go b/config/config_test.go index c70fdaf3d2..76264a1778 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -29,6 +29,7 @@ import ( "gopkg.in/yaml.v2" amcommoncfg "github.com/prometheus/alertmanager/config/common" + "github.com/prometheus/alertmanager/notify/email" ) func TestLoadEmptyString(t *testing.T) { @@ -782,7 +783,7 @@ func TestEmptyFieldsAndRegex(t *testing.T) { EnableHTTP2: true, }, ResolveTimeout: model.Duration(5 * time.Minute), - SMTPSmarthost: HostPort{Host: "localhost", Port: "25"}, + SMTPSmarthost: amcommoncfg.HostPort{Host: "localhost", Port: "25"}, SMTPFrom: "alertmanager@example.org", SMTPTLSConfig: &commoncfg.TLSConfig{ InsecureSkipVerify: false, @@ -828,11 +829,11 @@ func TestEmptyFieldsAndRegex(t *testing.T) { { Name: "team-X-mails", Labels: map[string]string{"name": "team-X-mails"}, - EmailConfigs: []*EmailConfig{ + EmailConfigs: []*email.EmailConfig{ { To: "team-X+alerts@example.org", From: "alertmanager@example.org", - Smarthost: HostPort{Host: "localhost", Port: "25"}, + Smarthost: amcommoncfg.HostPort{Host: "localhost", Port: "25"}, HTML: "{{ template \"email.default.html\" . }}", RequireTLS: &boolFoo, TLSConfig: &commoncfg.TLSConfig{ @@ -1587,73 +1588,6 @@ func TestRocketchatNoToken(t *testing.T) { } } -func TestUnmarshalHostPort(t *testing.T) { - for _, tc := range []struct { - in string - - exp HostPort - jsonOut string - yamlOut string - err bool - }{ - { - in: `""`, - exp: HostPort{}, - yamlOut: `"" -`, - jsonOut: `""`, - }, - { - in: `"localhost:25"`, - exp: HostPort{Host: "localhost", Port: "25"}, - yamlOut: `localhost:25 -`, - jsonOut: `"localhost:25"`, - }, - { - in: `":25"`, - exp: HostPort{Host: "", Port: "25"}, - yamlOut: `:25 -`, - jsonOut: `":25"`, - }, - { - in: `"localhost"`, - err: true, - }, - { - in: `"localhost:"`, - err: true, - }, - { - in: `"[fd12:3456:789a::1]:25"`, - exp: HostPort{Host: "fd12:3456:789a::1", Port: "25"}, - yamlOut: `'[fd12:3456:789a::1]:25' -`, - jsonOut: `"[fd12:3456:789a::1]:25"`, - }, - } { - t.Run(tc.in, func(t *testing.T) { - hp := HostPort{} - err := yaml.Unmarshal([]byte(tc.in), &hp) - if tc.err { - require.Error(t, err) - return - } - require.NoError(t, err) - require.Equal(t, tc.exp, hp) - - b, err := yaml.Marshal(&hp) - require.NoError(t, err) - require.Equal(t, tc.yamlOut, string(b)) - - b, err = json.Marshal(&hp) - require.NoError(t, err) - require.Equal(t, tc.jsonOut, string(b)) - }) - } -} - func TestNilRegexp(t *testing.T) { for _, tc := range []struct { file string diff --git a/config/notifiers.go b/notify/email/config.go similarity index 98% rename from config/notifiers.go rename to notify/email/config.go index 716661862e..e1ab65da9e 100644 --- a/config/notifiers.go +++ b/notify/email/config.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package config +package email import ( "errors" @@ -47,7 +47,7 @@ type EmailConfig struct { To string `yaml:"to,omitempty" json:"to,omitempty"` From string `yaml:"from,omitempty" json:"from,omitempty"` Hello string `yaml:"hello,omitempty" json:"hello,omitempty"` - Smarthost HostPort `yaml:"smarthost,omitempty" json:"smarthost,omitempty"` + Smarthost amcommoncfg.HostPort `yaml:"smarthost,omitempty" json:"smarthost,omitempty"` AuthUsername string `yaml:"auth_username,omitempty" json:"auth_username,omitempty"` AuthPassword commoncfg.Secret `yaml:"auth_password,omitempty" json:"auth_password,omitempty"` AuthPasswordFile string `yaml:"auth_password_file,omitempty" json:"auth_password_file,omitempty"` diff --git a/config/notifiers_test.go b/notify/email/config_test.go similarity index 98% rename from config/notifiers_test.go rename to notify/email/config_test.go index 06894f103b..6b0c1a7b0d 100644 --- a/config/notifiers_test.go +++ b/notify/email/config_test.go @@ -1,4 +1,4 @@ -// Copyright 2018 Prometheus Team +// Copyright The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package config +package email import ( "errors" diff --git a/notify/email/email.go b/notify/email/email.go index 246b366177..3c87e024b5 100644 --- a/notify/email/email.go +++ b/notify/email/email.go @@ -35,7 +35,6 @@ import ( commoncfg "github.com/prometheus/common/config" - "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/types" @@ -43,16 +42,16 @@ import ( // Email implements a Notifier for email notifications. type Email struct { - conf *config.EmailConfig + conf *EmailConfig tmpl *template.Template logger *slog.Logger hostname string } // New returns a new Email notifier. -func New(c *config.EmailConfig, t *template.Template, l *slog.Logger) *Email { +func New(c *EmailConfig, t *template.Template, l *slog.Logger) *Email { if _, ok := c.Headers["Subject"]; !ok { - c.Headers["Subject"] = config.DefaultEmailSubject + c.Headers["Subject"] = DefaultEmailSubject } if _, ok := c.Headers["To"]; !ok { c.Headers["To"] = c.To diff --git a/notify/email/email_test.go b/notify/email/email_test.go index 597dba8a3d..fdfba82cec 100644 --- a/notify/email/email_test.go +++ b/notify/email/email_test.go @@ -51,7 +51,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" - "github.com/prometheus/alertmanager/config" + amcommoncfg "github.com/prometheus/alertmanager/config/common" "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/types" @@ -147,10 +147,10 @@ func (m *mailDev) doEmailRequest(method, path string) (int, []byte, error) { // emailTestConfig is the configuration for the tests. type emailTestConfig struct { - Smarthost config.HostPort `yaml:"smarthost"` - Username string `yaml:"username"` - Password string `yaml:"password"` - Server *mailDev `yaml:"server"` + Smarthost amcommoncfg.HostPort `yaml:"smarthost"` + Username string `yaml:"username"` + Password string `yaml:"password"` + Server *mailDev `yaml:"server"` } func loadEmailTestConfiguration(f string) (emailTestConfig, error) { @@ -168,13 +168,13 @@ func loadEmailTestConfiguration(f string) (emailTestConfig, error) { return c, nil } -func notifyEmail(t *testing.T, cfg *config.EmailConfig, server *mailDev) (*email, bool, error) { +func notifyEmail(t *testing.T, cfg *EmailConfig, server *mailDev) (*email, bool, error) { return notifyEmailWithContext(context.Background(), t, cfg, server) } // notifyEmailWithContext sends a notification with one firing alert and retrieves the // email from the SMTP server if the notification has been successfully delivered. -func notifyEmailWithContext(ctx context.Context, t *testing.T, cfg *config.EmailConfig, server *mailDev) (*email, bool, error) { +func notifyEmailWithContext(ctx context.Context, t *testing.T, cfg *EmailConfig, server *mailDev) (*email, bool, error) { tmpl, firingAlert, err := prepare(cfg) if err != nil { return nil, false, err @@ -201,7 +201,7 @@ func notifyEmailWithContext(ctx context.Context, t *testing.T, cfg *config.Email return e, verdict.ShouldRetry(), nil } -func prepare(cfg *config.EmailConfig) (*template.Template, *types.Alert, error) { +func prepare(cfg *EmailConfig) (*template.Template, *types.Alert, error) { if cfg == nil { panic("nil config passed") } @@ -243,42 +243,42 @@ func TestEmailNotifyWithErrors(t *testing.T) { for _, tc := range []struct { title string - updateCfg func(*config.EmailConfig) + updateCfg func(*EmailConfig) errMsg string hasEmail bool }{ { title: "invalid 'from' template", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.From = `{{ template "invalid" }}` }, errMsg: "execute 'from' template:", }, { title: "invalid 'from' address", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.From = `xxx` }, errMsg: "parse 'from' addresses:", }, { title: "invalid 'to' template", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.To = `{{ template "invalid" }}` }, errMsg: "execute 'to' template:", }, { title: "invalid 'to' address", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.To = `xxx` }, errMsg: "parse 'to' addresses:", }, { title: "invalid 'subject' template", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.Headers["subject"] = `{{ template "invalid" }}` }, errMsg: `execute "subject" header template:`, @@ -286,7 +286,7 @@ func TestEmailNotifyWithErrors(t *testing.T) { }, { title: "invalid 'text' template", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.Text = `{{ template "invalid" }}` }, errMsg: `execute text template:`, @@ -294,7 +294,7 @@ func TestEmailNotifyWithErrors(t *testing.T) { }, { title: "invalid 'html' template", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.HTML = `{{ template "invalid" }}` }, errMsg: `execute html template:`, @@ -307,7 +307,7 @@ func TestEmailNotifyWithErrors(t *testing.T) { return } - emailCfg := &config.EmailConfig{ + emailCfg := &EmailConfig{ Smarthost: c.Smarthost, To: emailTo, From: emailFrom, @@ -354,7 +354,7 @@ func TestEmailNotifyWithDoneContext(t *testing.T) { _, _, err = notifyEmailWithContext( ctx, t, - &config.EmailConfig{ + &EmailConfig{ Smarthost: c.Smarthost, To: emailTo, From: emailFrom, @@ -383,7 +383,7 @@ func TestEmailNotifyWithoutAuthentication(t *testing.T) { mail, _, err := notifyEmail( t, - &config.EmailConfig{ + &EmailConfig{ Smarthost: c.Smarthost, To: emailTo, From: emailFrom, @@ -427,7 +427,7 @@ func TestEmailNotifyWithSTARTTLS(t *testing.T) { trueVar := true _, _, err = notifyEmail( t, - &config.EmailConfig{ + &EmailConfig{ Smarthost: c.Smarthost, To: emailTo, From: emailFrom, @@ -468,28 +468,28 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { for _, tc := range []struct { title string - updateCfg func(*config.EmailConfig) + updateCfg func(*EmailConfig) errMsg string retry bool }{ { title: "email with authentication", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPassword = commoncfg.Secret(c.Password) }, }, { title: "email with authentication (password from file)", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPasswordFile = fileWithCorrectPassword.Name() }, }, { title: "HTML-only email", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPassword = commoncfg.Secret(c.Password) cfg.Text = "" @@ -497,7 +497,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, { title: "text-only email", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPassword = commoncfg.Secret(c.Password) cfg.HTML = "" @@ -505,7 +505,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, { title: "multiple To addresses", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPassword = commoncfg.Secret(c.Password) cfg.To = strings.Join([]string{emailTo, emailFrom}, ",") @@ -513,7 +513,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, { title: "no more than one From address", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPassword = commoncfg.Secret(c.Password) cfg.From = strings.Join([]string{emailFrom, emailTo}, ",") @@ -524,7 +524,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, { title: "wrong credentials", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPassword = commoncfg.Secret(c.Password + "wrong") }, @@ -534,7 +534,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, { title: "wrong credentials (password from file)", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPasswordFile = fileWithIncorrectPassword.Name() }, @@ -544,7 +544,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, { title: "wrong credentials (missing password file)", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPasswordFile = "/does/not/exist" }, @@ -559,7 +559,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, { title: "try to enable STARTTLS", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.RequireTLS = new(bool) *cfg.RequireTLS = true }, @@ -569,7 +569,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, { title: "invalid Hello string", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthUsername = c.Username cfg.AuthPassword = commoncfg.Secret(c.Password) cfg.Hello = "invalid hello string" @@ -580,7 +580,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { }, } { t.Run(tc.title, func(t *testing.T) { - emailCfg := &config.EmailConfig{ + emailCfg := &EmailConfig{ Smarthost: c.Smarthost, To: emailTo, From: emailFrom, @@ -634,7 +634,7 @@ func TestEmailNotifyWithAuthentication(t *testing.T) { func TestEmailConfigNoAuthMechs(t *testing.T) { email := &Email{ - conf: &config.EmailConfig{AuthUsername: "test"}, tmpl: &template.Template{}, logger: promslog.NewNopLogger(), + conf: &EmailConfig{AuthUsername: "test"}, tmpl: &template.Template{}, logger: promslog.NewNopLogger(), } _, err := email.auth("") require.Error(t, err) @@ -642,7 +642,7 @@ func TestEmailConfigNoAuthMechs(t *testing.T) { } func TestEmailConfigMissingAuthParam(t *testing.T) { - conf := &config.EmailConfig{AuthUsername: "test"} + conf := &EmailConfig{AuthUsername: "test"} email := &Email{ conf: conf, tmpl: &template.Template{}, logger: promslog.NewNopLogger(), } @@ -665,7 +665,7 @@ func TestEmailConfigMissingAuthParam(t *testing.T) { func TestEmailNoUsernameStillOk(t *testing.T) { email := &Email{ - conf: &config.EmailConfig{}, tmpl: &template.Template{}, logger: promslog.NewNopLogger(), + conf: &EmailConfig{}, tmpl: &template.Template{}, logger: promslog.NewNopLogger(), } a, err := email.auth("CRAM-MD5") require.NoError(t, err) @@ -719,8 +719,8 @@ func TestEmailRejected(t *testing.T) { // Use mock SMTP server and prepare alert to be sent. require.IsType(t, &net.TCPAddr{}, l.Addr()) addr := l.Addr().(*net.TCPAddr) - cfg := &config.EmailConfig{ - Smarthost: config.HostPort{Host: addr.IP.String(), Port: strconv.Itoa(addr.Port)}, + cfg := &EmailConfig{ + Smarthost: amcommoncfg.HostPort{Host: addr.IP.String(), Port: strconv.Itoa(addr.Port)}, Hello: "localhost", Headers: make(map[string]string), From: "alertmanager@system", @@ -833,13 +833,13 @@ func TestEmailNotifyWithThreading(t *testing.T) { // Create context with group key (required for threading). ctx := notify.WithGroupKey(context.Background(), "test-group-key") - emailCfg := &config.EmailConfig{ + emailCfg := &EmailConfig{ Smarthost: c.Smarthost, To: emailTo, From: emailFrom, HTML: "HTML body", Text: "Text body", - Threading: config.ThreadingConfig{ + Threading: ThreadingConfig{ Enabled: true, ThreadByDate: tc.threadByDate, }, @@ -880,27 +880,27 @@ func TestEmailGetPassword(t *testing.T) { for _, tc := range []struct { title string - updateCfg func(*config.EmailConfig) + updateCfg func(*EmailConfig) errMsg string }{ { title: "password from field", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthPassword = "secret" cfg.AuthPasswordFile = "" }, }, { title: "password from file field", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthPassword = "" cfg.AuthPasswordFile = passwordFile.Name() }, }, { title: "password file path incorrect", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthPassword = "" cfg.AuthPasswordFile = "/does/not/exist" }, @@ -909,7 +909,7 @@ func TestEmailGetPassword(t *testing.T) { } { t.Run(tc.title, func(t *testing.T) { email := &Email{ - conf: &config.EmailConfig{}, + conf: &EmailConfig{}, } tc.updateCfg(email.conf) @@ -935,27 +935,27 @@ func TestEmailGetSecret(t *testing.T) { for _, tc := range []struct { title string - updateCfg func(*config.EmailConfig) + updateCfg func(*EmailConfig) errMsg string }{ { title: "secret from field", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthSecret = "secret" cfg.AuthSecretFile = "" }, }, { title: "secret from file field", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthSecret = "" cfg.AuthSecretFile = secretFile.Name() }, }, { title: "secret file path incorrect", - updateCfg: func(cfg *config.EmailConfig) { + updateCfg: func(cfg *EmailConfig) { cfg.AuthSecret = "" cfg.AuthSecretFile = "/does/not/exist" }, @@ -964,7 +964,7 @@ func TestEmailGetSecret(t *testing.T) { } { t.Run(tc.title, func(t *testing.T) { email := &Email{ - conf: &config.EmailConfig{}, + conf: &EmailConfig{}, } tc.updateCfg(email.conf) @@ -1029,8 +1029,8 @@ func TestEmailImplicitTLS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cfg := &config.EmailConfig{ - Smarthost: config.HostPort{Host: "localhost", Port: tt.port}, + cfg := &EmailConfig{ + Smarthost: amcommoncfg.HostPort{Host: "localhost", Port: tt.port}, ForceImplicitTLS: tt.forceImplicitTLS, }