From be44f61548d07c87bd611d46dda8a3de8be3e501 Mon Sep 17 00:00:00 2001 From: shkaruna Date: Tue, 23 Jun 2026 14:01:37 +0530 Subject: [PATCH] feat: add aclp alert channel API support --- monitor_alert_channels.go | 24 +++++ ...nitions_test.go => monitor_alerts_test.go} | 46 ++++++++ test/unit/monitor_alert_channels_test.go | 100 ++++++++++++++---- 3 files changed, 148 insertions(+), 22 deletions(-) rename test/integration/{monitor_alert_definitions_test.go => monitor_alerts_test.go} (88%) diff --git a/monitor_alert_channels.go b/monitor_alert_channels.go index 7de93d86e..7ca6e6217 100644 --- a/monitor_alert_channels.go +++ b/monitor_alert_channels.go @@ -77,8 +77,32 @@ func (a *AlertChannel) UnmarshalJSON(b []byte) error { return nil } +// AlertChannelCreateOptions represents options for creating an alert notification channel. +type AlertChannelCreateOptions struct { + ChannelType AlertNotificationType `json:"channel_type"` + Details AlertChannelDetailsOptions `json:"details"` + Label *string `json:"label,omitzero"` +} + +// AlertChannelDetailsOptions represents the details configuration for an alert channel. +type AlertChannelDetailsOptions struct { + Email *EmailChannelCreateOptions `json:"email,omitzero"` +} + +// EmailChannelCreateOptions represents email-specific configuration for an alert channel. +type EmailChannelCreateOptions struct { + Usernames []string `json:"usernames"` + RecipientType *string `json:"recipient_type,omitzero"` +} + // ListAlertChannels gets a paginated list of Alert Channels. func (c *Client) ListAlertChannels(ctx context.Context, opts *ListOptions) ([]AlertChannel, error) { endpoint := formatAPIPath("monitor/alert-channels") return getPaginatedResults[AlertChannel](ctx, c, endpoint, opts) } + +// CreateAlertChannel creates a new alert notification channel. +func (c *Client) CreateAlertChannel(ctx context.Context, opts AlertChannelCreateOptions) (*AlertChannel, error) { + endpoint := formatAPIPath("monitor/alert-channels") + return doPOSTRequest[AlertChannel](ctx, c, endpoint, opts) +} diff --git a/test/integration/monitor_alert_definitions_test.go b/test/integration/monitor_alerts_test.go similarity index 88% rename from test/integration/monitor_alert_definitions_test.go rename to test/integration/monitor_alerts_test.go index 42050d3d9..3b306c1e8 100644 --- a/test/integration/monitor_alert_definitions_test.go +++ b/test/integration/monitor_alerts_test.go @@ -8,6 +8,7 @@ import ( "github.com/linode/linodego/v2" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const ( @@ -331,3 +332,48 @@ func TestMonitorAlertDefinitionEntities_List(t *testing.T) { assert.NotEmpty(t, entity.URL) } } + +func TestMonitorAlertChannel_Create_smoke(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestMonitorAlertChannel_Create") + defer teardown() + + profile, err := client.GetProfile(context.Background()) //To supply a valid email recipient username + require.NoError(t, err) + require.NotEmpty(t, profile.Username) + + label := "go-test-alert-channel-create-" + getUniqueText() + recipientType := "user" + + createOpts := linodego.AlertChannelCreateOptions{ + ChannelType: linodego.EmailAlertNotification, + Label: &label, + Details: linodego.AlertChannelDetailsOptions{ + Email: &linodego.EmailChannelCreateOptions{ + Usernames: []string{profile.Username}, + RecipientType: &recipientType, + }, + }, + } + + channel, err := client.CreateAlertChannel(context.Background(), createOpts) + require.NoError(t, err) + require.NotNil(t, channel) + + assert.NotZero(t, channel.ID) + assert.Equal(t, label, channel.Label) + assert.Equal(t, createOpts.ChannelType, channel.ChannelType) + assert.Equal(t, linodego.UserAlertChannel, channel.Type) + + require.NotNil(t, channel.Details.Email) + assert.Equal(t, createOpts.Details.Email.Usernames, channel.Details.Email.Usernames) + assert.Equal(t, recipientType, channel.Details.Email.RecipientType) + + assert.NotEmpty(t, channel.Alerts.URL) + assert.NotEmpty(t, channel.Alerts.Type) + assert.GreaterOrEqual(t, channel.Alerts.AlertCount, 0) + + assertDateSet(t, channel.Created) + assertDateSet(t, channel.Updated) + + // Intentionally no cleanup: delete API for monitor alert channels is not available. +} diff --git a/test/unit/monitor_alert_channels_test.go b/test/unit/monitor_alert_channels_test.go index 6b4bac32f..ba5bca222 100644 --- a/test/unit/monitor_alert_channels_test.go +++ b/test/unit/monitor_alert_channels_test.go @@ -10,35 +10,59 @@ import ( "github.com/stretchr/testify/require" ) -const monitorAlertChannelListResponse = `{ - "data": [{ - "id": 123, - "label": "alert notification channel", +const ( + monitorAlertChannelListResponse = `{ + "data": [{ + "id": 123, + "label": "alert notification channel", + "channel_type": "email", + "type": "user", + "details": { + "email": { + "usernames": [ + "admin-user1", + "admin-user2" + ], + "recipient_type": "user" + } + }, + "alerts": { + "url": "/monitor/alert-channels/123/alerts", + "type": "alerts-definitions", + "alert_count": 0 + }, + "created": "2024-01-01T00:00:00", + "updated": "2024-01-01T00:00:00", + "created_by": "tester", + "updated_by": "tester" + }], + "page": 1, + "pages": 1, + "results": 1 + }` + + monitorAlertChannelCreateResponse = `{ + "id": 10000, + "label": "My Email Alert Channel", "channel_type": "email", "type": "user", + "created": "2026-06-23T09:43:00", + "created_by": "johndoe", + "updated": "2026-06-23T09:43:00", + "updated_by": "johndoe", "details": { "email": { - "usernames": [ - "admin-user1", - "admin-user2" - ], - "recipient_type": "user" + "recipient_type": "user", + "usernames": ["johndoe", "janedoe"] } }, "alerts": { - "url": "/monitor/alert-channels/123/alerts", - "type": "alerts-definitions", - "alert_count": 0 - }, - "created": "2024-01-01T00:00:00", - "updated": "2024-01-01T00:00:00", - "created_by": "tester", - "updated_by": "tester" - }], - "page": 1, - "pages": 1, - "results": 1 -}` + "alert_count": 0, + "type": "alert-definitions", + "url": "/monitor/alert-channels/10000/alerts" + } + }` +) func TestListAlertChannels(t *testing.T) { var base ClientBaseCase @@ -62,3 +86,35 @@ func TestListAlertChannels(t *testing.T) { assert.Equal(t, 0, channel.Alerts.AlertCount) assert.Equal(t, "/monitor/alert-channels/123/alerts", channel.Alerts.URL) } + +func TestCreateAlertChannel(t *testing.T) { + var base ClientBaseCase + base.SetUp(t) + defer base.TearDown(t) + + base.MockPost("monitor/alert-channels", json.RawMessage(monitorAlertChannelCreateResponse)) + + opts := linodego.AlertChannelCreateOptions{ + ChannelType: linodego.EmailAlertNotification, + Label: linodego.Pointer("My Email Alert Channel"), + Details: linodego.AlertChannelDetailsOptions{ + Email: &linodego.EmailChannelCreateOptions{ + Usernames: []string{"johndoe", "janedoe"}, + }, + }, + } + + channel, err := base.Client.CreateAlertChannel(context.Background(), opts) + require.NoError(t, err) + require.NotNil(t, channel) + + assert.Equal(t, 10000, channel.ID) + assert.Equal(t, "My Email Alert Channel", channel.Label) + assert.Equal(t, linodego.EmailAlertNotification, channel.ChannelType) + assert.Equal(t, linodego.UserAlertChannel, channel.Type) + require.NotNil(t, channel.Details.Email) + assert.Equal(t, []string{"johndoe", "janedoe"}, channel.Details.Email.Usernames) + assert.Equal(t, "user", channel.Details.Email.RecipientType) + assert.Equal(t, 0, channel.Alerts.AlertCount) + assert.Equal(t, "/monitor/alert-channels/10000/alerts", channel.Alerts.URL) +}