Skip to content

Commit f4ab4af

Browse files
committed
adding create channel api changes
1 parent fcc41e5 commit f4ab4af

5 files changed

Lines changed: 238 additions & 7 deletions

File tree

‎linode_api4/groups/monitor.py‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
MonitorService,
1414
MonitorServiceToken,
1515
)
16+
from linode_api4.objects.monitor import ChannelDetails
1617

1718
__all__ = [
1819
"MonitorGroup",
@@ -332,3 +333,64 @@ def alert_definition_entities(
332333
*filters,
333334
endpoint=endpoint,
334335
)
336+
337+
def channel_create(
338+
self,
339+
label: str,
340+
channel_type: str,
341+
details: ChannelDetails,
342+
) -> AlertChannel:
343+
"""
344+
Creates a new alert channel for the authenticated account.
345+
346+
An alert channel defines a notification destination (for example: an
347+
email list) that can be associated with one or more alert definitions.
348+
Currently only ``email`` is supported as a ``channel_type``.
349+
350+
Example usage::
351+
352+
from linode_api4.objects.monitor import ChannelDetails, EmailDetails
353+
354+
client = LinodeClient(TOKEN)
355+
356+
new_channel = client.monitor.channel_create(
357+
label="Email channel for api change",
358+
channel_type="email",
359+
details=ChannelDetails(
360+
email=EmailDetails(
361+
recipient_type="user",
362+
usernames=["username-test"],
363+
)
364+
),
365+
)
366+
367+
API Documentation: https://techdocs.akamai.com/linode-api/reference/post-alert-channel
368+
369+
:param label: Human-readable name for the new alert channel.
370+
:type label: str
371+
:param channel_type: The type of notification channel (e.g. ``"email"``).
372+
:type channel_type: str
373+
:param details: Notification-type-specific configuration. Use
374+
:class:`~linode_api4.objects.monitor.ChannelDetails` with
375+
a nested :class:`~linode_api4.objects.monitor.EmailDetails`
376+
for email channels.
377+
:type details: ChannelDetails
378+
379+
:returns: The newly created :class:`AlertChannel`.
380+
:rtype: AlertChannel
381+
"""
382+
params = {
383+
"label": label,
384+
"channel_type": channel_type,
385+
"details": details.dict,
386+
}
387+
388+
result = self.client.post("/monitor/alert-channels", data=params)
389+
390+
if "id" not in result:
391+
raise UnexpectedResponseError(
392+
"Unexpected response when creating alert channel!",
393+
json=result,
394+
)
395+
396+
return AlertChannel(self.client, result["id"], result)

‎linode_api4/objects/monitor.py‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -492,13 +492,12 @@ class AlertChannel(Base):
492492
fire. Alert channels define a destination and configuration for
493493
notifications (for example: email lists, webhooks, PagerDuty, Slack, etc.).
494494
495-
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-notification-channels
495+
API Documentation:
496+
List/Get: https://techdocs.akamai.com/linode-api/reference/get-alert-channels
497+
Create: https://techdocs.akamai.com/linode-api/reference/post-alert-channel
496498
497-
This class maps to the Monitor API's `/monitor/alert-channels` resource
498-
and is used by the SDK to list, load, and inspect channels.
499-
500-
NOTE: Only read operations are supported for AlertChannel at this time.
501-
Create, update, and delete (CRUD) operations are not allowed.
499+
This class maps to the Monitor API's ``/monitor/alert-channels`` resource
500+
and is used by the SDK to list, load, create, and inspect channels.
502501
"""
503502

504503
api_endpoint = "/monitor/alert-channels/{id}"

‎test/integration/models/monitor/test_monitor.py‎

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from linode_api4 import LinodeClient, PaginatedList
1111
from linode_api4.objects import (
12+
AlertChannel,
1213
AlertDefinition,
1314
AlertDefinitionEntity,
1415
ApiError,
@@ -17,7 +18,7 @@
1718
MonitorService,
1819
MonitorServiceToken,
1920
)
20-
from linode_api4.objects.monitor import AlertStatus
21+
from linode_api4.objects.monitor import AlertStatus, ChannelDetails, EmailDetails
2122

2223

2324
# List all dashboards
@@ -311,3 +312,61 @@ def test_alert_definition_entities(test_linode_client):
311312
assert entity.label
312313
assert entity.url
313314
assert entity._type == service_type
315+
316+
317+
def test_integration_create_get_delete_alert_channel(test_linode_client):
318+
"""E2E: create an alert channel, fetch it, then delete it.
319+
320+
This test creates an alert channel with email details, retrieves it,
321+
and then deletes it. It ensures the feature is working end-to-end
322+
against the actual API.
323+
"""
324+
client = test_linode_client
325+
label = get_test_label() + "-e2e-channel"
326+
label = f"{label}-{int(time.time())}"
327+
328+
created_channel = None
329+
330+
try:
331+
# Create an alert channel with email details
332+
created_channel = client.monitor.channel_create(
333+
label=label,
334+
channel_type="email",
335+
details=ChannelDetails(
336+
email=EmailDetails(
337+
recipient_type="user",
338+
usernames=["mawasthy_tenant02_admin"],
339+
)
340+
),
341+
)
342+
343+
# Assert the created channel has expected properties
344+
assert isinstance(created_channel, AlertChannel)
345+
assert created_channel.id is not None
346+
assert created_channel.label == label
347+
assert created_channel.channel_type == "email"
348+
assert created_channel.details is not None
349+
350+
# Fetch the channel to verify it exists
351+
channels = list(client.monitor.alert_channels())
352+
assert len(channels) > 0, "No channels found after creation"
353+
354+
# Find the created channel in the list
355+
found_channel = None
356+
for ch in channels:
357+
if ch.id == created_channel.id:
358+
found_channel = ch
359+
break
360+
361+
assert found_channel is not None, "Created channel not found in list"
362+
assert found_channel.label == label
363+
assert found_channel.channel_type == "email"
364+
365+
finally:
366+
if created_channel:
367+
# Clean up: delete the created channel
368+
try:
369+
created_channel.delete()
370+
except Exception as e:
371+
# Log but don't fail if cleanup fails
372+
print(f"Warning: Failed to delete channel {created_channel.id}: {e}")

‎test/unit/groups/monitor_api_test.py‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
from linode_api4 import PaginatedList
44
from linode_api4.objects import (
55
AggregateFunction,
6+
AlertChannel,
67
AlertDefinition,
78
AlertDefinitionChannel,
89
AlertDefinitionEntity,
910
EntityMetricOptions,
1011
)
12+
from linode_api4.objects.monitor import ChannelDetails, EmailDetails
1113

1214

1315
class MonitorAPITest(MonitorClientBaseCase):
@@ -180,3 +182,55 @@ def test_alert_definition_entities(self):
180182
assert entities[2].label == "mydatabase-3"
181183
assert entities[2].url == "/v4/databases/mysql/instances/3"
182184
assert entities[2]._type == "dbaas"
185+
186+
def test_create_channel(self):
187+
url = "/monitor/alert-channels"
188+
result = {
189+
"id": 123,
190+
"label": "email channel for api change",
191+
"type": "user",
192+
"channel_type": "email",
193+
"details": {
194+
"email": {
195+
"usernames": ["mawasthy_tenant02_admin"],
196+
"recipient_type": "user",
197+
}
198+
},
199+
"alerts": {
200+
"url": "/monitor/alert-channels/123/alerts",
201+
"type": "alerts-definitions",
202+
"alert_count": 0,
203+
},
204+
"created": "2024-01-01T00:00:00",
205+
"updated": "2024-01-01T00:00:00",
206+
"created_by": "mawasthy_tenant02_admin",
207+
"updated_by": "mawasthy_tenant02_admin",
208+
}
209+
210+
with self.mock_post(result) as mock_post:
211+
channel = self.client.monitor.channel_create(
212+
label="email channel for api change",
213+
channel_type="email",
214+
details=ChannelDetails(
215+
email=EmailDetails(
216+
recipient_type="user",
217+
usernames=["mawasthy_tenant02_admin"],
218+
)
219+
),
220+
)
221+
222+
assert mock_post.call_url == url
223+
# payload should include the provided fields
224+
assert mock_post.call_data["label"] == "email channel for api change"
225+
assert mock_post.call_data["channel_type"] == "email"
226+
assert "details" in mock_post.call_data
227+
228+
assert isinstance(channel, AlertChannel)
229+
assert channel.id == 123
230+
assert channel.label == "email channel for api change"
231+
assert channel.channel_type == "email"
232+
233+
# fetch the same response from the client and assert
234+
resp = self.client.post(url, data={})
235+
assert resp["label"] == "email channel for api change"
236+
assert resp["channel_type"] == "email"

‎test/unit/objects/monitor_test.py‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from test.unit.base import ClientBaseCase
33

44
from linode_api4.objects import AlertChannel, MonitorDashboard, MonitorService
5+
from linode_api4.objects.monitor import ChannelDetails, EmailDetails
56

67

78
class MonitorTest(ClientBaseCase):
@@ -169,3 +170,59 @@ def test_alert_channels(self):
169170
"/monitor/alert-channels/123/alerts",
170171
)
171172
self.assertEqual(channels[0].alerts.alert_count, 0)
173+
174+
def test_create_channel(self):
175+
176+
create_response = {
177+
"id": 456,
178+
"label": "Email channel for api change",
179+
"type": "user",
180+
"channel_type": "email",
181+
"details": {
182+
"email": {
183+
"recipient_type": "user",
184+
"usernames": ["mawasthy_tenant02_admin"],
185+
}
186+
},
187+
"alerts": {
188+
"url": "/monitor/alert-channels/456/alerts",
189+
"type": "alerts-definitions",
190+
"alert_count": 0,
191+
},
192+
"created": "2024-01-01T00:00:00",
193+
"updated": "2024-01-01T00:00:00",
194+
"created_by": "mawasthy_tenant02_admin",
195+
"updated_by": "mawasthy_tenant02_admin",
196+
}
197+
198+
with self.mock_post(create_response) as m:
199+
result = self.client.monitor.channel_create(
200+
label="Email channel for api change",
201+
channel_type="email",
202+
details=ChannelDetails(
203+
email=EmailDetails(
204+
recipient_type="user",
205+
usernames=["mawasthy_tenant02_admin"],
206+
)
207+
),
208+
)
209+
210+
self.assertEqual(m.call_url, "/monitor/alert-channels")
211+
self.assertEqual(m.call_data["label"], "Email channel for api change")
212+
self.assertEqual(m.call_data["channel_type"], "email")
213+
self.assertEqual(
214+
m.call_data["details"]["email"]["recipient_type"], "user"
215+
)
216+
self.assertEqual(
217+
m.call_data["details"]["email"]["usernames"], ["mawasthy_tenant02_admin"]
218+
)
219+
220+
self.assertIsInstance(result, AlertChannel)
221+
self.assertEqual(result.id, 456)
222+
self.assertEqual(result.label, "Email channel for api change")
223+
self.assertEqual(result.type, "user")
224+
self.assertEqual(result.channel_type, "email")
225+
self.assertIsNotNone(result.details)
226+
self.assertIsNotNone(result.details.email)
227+
self.assertEqual(result.details.email.recipient_type, "user")
228+
self.assertEqual(result.details.email.usernames, ["mawasthy_tenant02_admin"])

0 commit comments

Comments
 (0)