mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-03 08:33:26 +00:00
fix(alertmanager): disallow creating invalid channels (#9946)
This commit is contained in:
@@ -2,9 +2,10 @@ package signozalertmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/query-service/utils/labels"
|
||||
"github.com/prometheus/common/model"
|
||||
"time"
|
||||
|
||||
amConfig "github.com/prometheus/alertmanager/config"
|
||||
|
||||
@@ -191,7 +192,11 @@ func (provider *provider) CreateChannel(ctx context.Context, orgID string, recei
|
||||
return err
|
||||
}
|
||||
|
||||
channel := alertmanagertypes.NewChannelFromReceiver(receiver, orgID)
|
||||
channel, err := alertmanagertypes.NewChannelFromReceiver(receiver, orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return provider.configStore.CreateChannel(ctx, channel, alertmanagertypes.WithCb(func(ctx context.Context) error {
|
||||
return provider.configStore.Set(ctx, config)
|
||||
}))
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
var (
|
||||
ErrCodeAlertmanagerChannelNotFound = errors.MustNewCode("alertmanager_channel_not_found")
|
||||
ErrCodeAlertmanagerChannelNameMismatch = errors.MustNewCode("alertmanager_channel_name_mismatch")
|
||||
ErrCodeAlertmanagerChannelInvalid = errors.MustNewCode("alertmanager_channel_invalid")
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -41,9 +42,9 @@ type Channel struct {
|
||||
|
||||
// NewChannelFromReceiver creates a new Channel from a Receiver.
|
||||
// It can return nil if the receiver is the default receiver.
|
||||
func NewChannelFromReceiver(receiver config.Receiver, orgID string) *Channel {
|
||||
func NewChannelFromReceiver(receiver config.Receiver, orgID string) (*Channel, error) {
|
||||
if receiver.Name == DefaultReceiverName {
|
||||
return nil
|
||||
return nil, errors.Newf(errors.TypeInvalidInput, ErrCodeAlertmanagerChannelInvalid, "cannot use %s name as a channel name", receiver.Name)
|
||||
}
|
||||
|
||||
// Initialize channel with common fields
|
||||
@@ -98,7 +99,12 @@ func NewChannelFromReceiver(receiver config.Receiver, orgID string) *Channel {
|
||||
break
|
||||
}
|
||||
|
||||
return &channel
|
||||
// If we were unable to find the channel type, return an error
|
||||
if channel.Type == "" {
|
||||
return nil, errors.Newf(errors.TypeInvalidInput, ErrCodeAlertmanagerChannelInvalid, "channel '%s' must have at least one notification configuration (e.g., email_configs, webhook_configs, slack_configs)", receiver.Name)
|
||||
}
|
||||
|
||||
return &channel, nil
|
||||
}
|
||||
|
||||
func NewConfigFromChannels(globalConfig GlobalConfig, routeConfig RouteConfig, channels Channels, orgID string) (*Config, error) {
|
||||
@@ -163,9 +169,9 @@ func NewStatsFromChannels(channels Channels) map[string]any {
|
||||
}
|
||||
|
||||
func (c *Channel) Update(receiver Receiver) error {
|
||||
channel := NewChannelFromReceiver(receiver, c.OrgID)
|
||||
if channel == nil {
|
||||
return errors.Newf(errors.TypeInvalidInput, ErrCodeAlertmanagerChannelNotFound, "cannot find channel with id %s", c.ID.StringValue())
|
||||
channel, err := NewChannelFromReceiver(receiver, c.OrgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Name != channel.Name {
|
||||
|
||||
@@ -2,6 +2,7 @@ package alertmanagertypes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -228,3 +229,66 @@ func TestNewConfigFromChannels(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewChannelFromReceiver(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
receiver config.Receiver
|
||||
expected *Channel
|
||||
pass bool
|
||||
}{
|
||||
{
|
||||
name: "InvalidReceiver_OnlyName",
|
||||
receiver: config.Receiver{
|
||||
Name: "test-receiver",
|
||||
},
|
||||
expected: nil,
|
||||
pass: false,
|
||||
},
|
||||
{
|
||||
name: "InvalidReceiver_DefaultReceiver",
|
||||
receiver: config.Receiver{
|
||||
Name: DefaultReceiverName,
|
||||
},
|
||||
expected: nil,
|
||||
pass: false,
|
||||
},
|
||||
{
|
||||
name: "ValidReceiver_Slack",
|
||||
receiver: config.Receiver{
|
||||
Name: "test-receiver",
|
||||
SlackConfigs: []*config.SlackConfig{
|
||||
{
|
||||
Channel: "#alerts",
|
||||
APIURL: &config.SecretURL{URL: &url.URL{Scheme: "https", Host: "slack.com", Path: "/api/test"}},
|
||||
NotifierConfig: config.NotifierConfig{
|
||||
VSendResolved: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &Channel{
|
||||
Name: "test-receiver",
|
||||
Type: "slack",
|
||||
Data: `{"name":"test-receiver","slack_configs":[{"send_resolved":true,"api_url":"https://slack.com/api/test","channel":"#alerts"}]}`,
|
||||
},
|
||||
pass: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
channel, err := NewChannelFromReceiver(testCase.receiver, "1")
|
||||
if !testCase.pass {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, testCase.expected.Name, channel.Name)
|
||||
assert.Equal(t, testCase.expected.Type, channel.Type)
|
||||
assert.Equal(t, testCase.expected.Data, channel.Data)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user