Skip to content

Commit 546d3fb

Browse files
committed
DI-26927 fixed review comments from API v4 team
1 parent 49da6b8 commit 546d3fb

File tree

3 files changed

+70
-162
lines changed

3 files changed

+70
-162
lines changed

linode_api4/groups/monitor.py

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ def get_alert_definitions(
155155
self,
156156
*filters,
157157
service_type: Optional[str] = None,
158-
alert_id: Optional[int] = None,
159158
) -> Union[PaginatedList, AlertDefinition]:
160159
"""
161160
Retrieve one or more alert definitions.
@@ -167,7 +166,7 @@ def get_alert_definitions(
167166
168167
Examples:
169168
alert_definitions = client.monitor.get_alert_definitions()
170-
alert_definition = client.monitor.get_alert_definitions(service_type="dbaas", alert_id=1234)
169+
alert_definition = client.load(AlertDefinition, alert_id,"dbaas")
171170
alert_definitions_for_service = client.monitor.get_alert_definitions(service_type="dbaas")
172171
173172
.. note:: This endpoint is in beta and requires using the v4beta base URL.
@@ -193,19 +192,9 @@ def get_alert_definitions(
193192
:rtype: Union[AlertDefinition, PaginatedList[AlertDefinition]]
194193
"""
195194

196-
if alert_id is not None and service_type is None:
197-
raise ValueError(
198-
"service_type must be provided when alert_id is specified"
199-
)
200-
201195
endpoint = "/monitor/alert-definitions"
202196
if service_type:
203197
endpoint = f"/monitor/services/{service_type}/alert-definitions"
204-
if alert_id:
205-
endpoint = f"{endpoint}/{alert_id}"
206-
# Requesting a single object
207-
alert_json = self.client.get(endpoint)
208-
return AlertDefinition(self.client, alert_id, alert_json)
209198

210199
# Requesting a list
211200
return self.client._get_and_filter(
@@ -304,7 +293,7 @@ def create_alert_definition(
304293
json=result,
305294
)
306295

307-
return AlertDefinition(self.client, result["id"], result)
296+
return AlertDefinition(self.client, result["id"],service_type, result)
308297

309298
def update_alert_definition(
310299
self,
@@ -375,26 +364,4 @@ def update_alert_definition(
375364
data=params,
376365
)
377366

378-
return AlertDefinition(self.client, result["id"], result)
379-
380-
def delete_alert_definition(
381-
self, service_type: str, alert_id: int
382-
) -> None:
383-
"""
384-
Delete an alert definition.
385-
386-
.. note:: This endpoint is in beta and requires using the v4beta base URL.
387-
388-
API Documentation: https://techdocs.akamai.com/linode-api/reference/delete-alert-definition
389-
390-
:param service_type: Service type of the alert definition to delete
391-
(e.g. ``"dbaas"``).
392-
:type service_type: str
393-
:param alert_id: ID of the alert definition to delete.
394-
:type alert_id: int
395-
396-
:returns: None
397-
"""
398-
self.client.delete(
399-
f"/monitor/services/{service_type}/alert-definitions/{alert_id}"
400-
)
367+
return AlertDefinition(self.client, result["id"], service_type, result)

linode_api4/objects/monitor.py

Lines changed: 61 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
__all__ = [
2+
"AlertType",
23
"MonitorDashboard",
34
"MonitorMetricsDefinition",
45
"MonitorService",
@@ -8,14 +9,14 @@
89
"TriggerConditions",
910
"AlertChannel",
1011
"AlertDefinition",
11-
"AlertType",
1212
"AlertChannelEnvelope",
1313
]
1414
from dataclasses import dataclass, field
1515
from enum import Enum
1616
from typing import List, Literal, Optional, Union
1717

1818
from linode_api4.objects.base import Base, Property
19+
from linode_api4.objects import DerivedBase
1920
from linode_api4.objects.serializable import JSONObject, StrEnum
2021

2122

@@ -288,69 +289,53 @@ class AlertChannelEnvelope(JSONObject):
288289
type: str = ""
289290
url: str = ""
290291

291-
class AlertDefinition(Base):
292+
@dataclass
293+
class AlertType(Enum):
292294
"""
293-
Represents an alert definition for a monitor service.
295+
Enumeration of alert origin types used by alert definitions.
294296
295-
This object models the JSON returned by the Monitor API's alert-definition
296-
endpoints. Alert definitions describe a named condition (one or more rules)
297-
that, when met, will trigger notifications via configured alert channels.
298-
299-
Typical usage:
300-
alert = client.monitor.alert_definitions(service_type="dbaas", alert_id=1234)
301-
alerts = client.monitor.alert_definitions(service_type="dbaas")
302-
303-
Important fields encoded in the API response include:
304-
- id: int - Unique identifier for the alert definition.
305-
- label: str - Human-readable name for the alert.
306-
- severity: str/int - Severity level (e.g. "warning", "critical").
307-
- type: str - "user" or "system" indicating origin.
308-
- service_type: str - The service type the alert applies to (e.g. "dbaas").
309-
- status: str - Current status of the alert definition (e.g. "active").
310-
- rule_criteria: dict - The set of rules evaluated to determine whether
311-
an alert should trigger (see :class:`RuleCriteria`).
312-
- trigger_conditions: dict - Evaluation configuration (see :class:`TriggerConditions`).
313-
- alert_channels: list - A list of lightweight channel envelopes
314-
(:class:`AlertChannelEnvelope`) used to notify when the alert fires.
315-
- entity_ids: list - Optional list of entity IDs this alert targets.
316-
- created / updated / updated_by / created_by - Auditing metadata.
317-
318-
Note: The API returns a key named "class" which is a reserved word in
319-
Python. When populating this object the value is stored on the attribute
320-
``_class``.
297+
Values:
298+
- SYSTEM: Alerts that originate from the system (built-in or platform-managed).
299+
- USER: Alerts created and managed by users (custom alerts).
300+
301+
The API uses this value in the `type` field of alert-definition responses.
302+
This enum can be used to compare or validate the `type` value when
303+
processing alert definitions.
304+
"""
305+
SYSTEM = "system"
306+
USER = "user"
307+
308+
class AlertDefinition(DerivedBase):
309+
"""
310+
Represents an alert definition for a monitor service.
321311
322312
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-alert-definition
323313
"""
324-
id: int
325-
label: str
326-
severity: int
327-
_type: str
328-
service_type: str
329-
status: str
330-
has_more_resources: bool
331-
rule_criteria: list[Rule]
332-
trigger_conditions: TriggerConditions
333-
alert_channels: list[AlertChannelEnvelope]
334-
created: str
335-
updated: str
336-
updated_by: str
337-
created_by: str
338-
entity_ids: list[str] = None
339-
description: str = None
340-
_class: str = None
341-
342-
343-
def __init__(self, client, id, json=None):
344-
super().__init__(client, id, json)
345-
346-
def _populate(self, json):
347-
"""
348-
Populates this object with data from a JSON dictionary.
349-
"""
350-
reserved = {"class": "_class", "type": "_type"}
351-
for json_key, json_value in json.items():
352-
attr = reserved.get(json_key, json_key)
353-
setattr(self, attr, json_value)
314+
315+
api_endpoint = "/monitor/services/{service}/alert-definitions/{id}"
316+
derived_url_path = "alert-definitions"
317+
parent_id_name = "service"
318+
id_attribute = "id"
319+
320+
properties = {
321+
"id": Property(identifier=True),
322+
"label": Property(),
323+
"severity": Property(),
324+
"type": Property(AlertType),
325+
"service_type": Property(mutable=True),
326+
"status": Property(mutable=True),
327+
"has_more_resources": Property(mutable=True),
328+
"rule_criteria": Property(RuleCriteria),
329+
"trigger_conditions": Property(TriggerConditions),
330+
"alert_channels": Property(List[AlertChannelEnvelope]),
331+
"created": Property(is_datetime=True),
332+
"updated": Property(is_datetime=True),
333+
"updated_by": Property(),
334+
"created_by": Property(),
335+
"entity_ids": Property(List[str]),
336+
"description": Property(),
337+
"_class": Property("class"),
338+
}
354339

355340

356341
@dataclass
@@ -367,22 +352,6 @@ class ChannelContent(JSONObject):
367352
"""
368353
email: EmailChannelContent = None
369354
# Other channel types like 'webhook', 'slack' could be added here as Optional fields.
370-
371-
@dataclass
372-
class AlertType(Enum):
373-
"""
374-
Enumeration of alert origin types used by alert definitions.
375-
376-
Values:
377-
- SYSTEM: Alerts that originate from the system (built-in or platform-managed).
378-
- USER: Alerts created and managed by users (custom alerts).
379-
380-
The API uses this value in the `type` field of alert-definition responses.
381-
This enum can be used to compare or validate the `type` value when
382-
processing alert definitions.
383-
"""
384-
SYSTEM = "system"
385-
USER = "user"
386355

387356
class AlertChannel(Base):
388357
"""
@@ -391,43 +360,22 @@ class AlertChannel(Base):
391360
notifications (for example: email lists, webhooks, PagerDuty, Slack, etc.).
392361
393362
This class maps to the Monitor API's `/monitor/alert-channels` resource
394-
and is used by the SDK to list, load, and inspect channels. Typical fields
395-
returned by the API include:
396-
- id: int - Unique identifier for the channel
397-
- label: str - Human readable label for the channel
398-
- type / channel_type: str - Channel type ("email", "webhook", "pagerduty", ...)
399-
- url: str - URL or destination associated with the channel (when applicable)
400-
- content: dict - Channel-specific configuration block (e.g. email addresses)
401-
- created / updated / created_by / updated_by - Auditing metadata
402-
403-
Note: The exact shape of the `content` block varies by channel type; the
404-
SDK exposes `ChannelContent` / `EmailChannelContent` dataclasses for common
405-
cases but callers may receive raw dicts from the API in some responses.
363+
and is used by the SDK to list, load, and inspect channels.
406364
"""
365+
407366
api_endpoint = "/monitor/alert-channels/"
408-
id: int
409-
alerts: List[AlertChannelEnvelope]
410-
label: str
411-
channel_type: str
412-
content: ChannelContent
413-
created: str
414-
created_by: str
415-
_type: AlertType
416-
updated: str
417-
updated_by: str
418-
419-
@property
420-
def type(self):
421-
return self._type
422-
423-
@type.setter
424-
def type(self, value):
425-
self._type = value
426-
427-
def _populate(self, json):
428-
"""
429-
Populates this object with data from a JSON dictionary.
430-
"""
431-
for key, value in json.items():
432-
if hasattr(self, key):
433-
setattr(self, key, value)
367+
id_attribute = "id"
368+
369+
properties = {
370+
"id": Property(identifier=True),
371+
"label": Property(),
372+
"type": Property("channel_type"),
373+
"channel_type": Property(),
374+
"content": Property(ChannelContent),
375+
"created": Property(is_datetime=True),
376+
"updated": Property(is_datetime=True),
377+
"created_by": Property(),
378+
"updated_by": Property(),
379+
"url": Property(),
380+
# Add other fields as needed
381+
}

test/integration/models/monitor/test_monitor.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from linode_api4 import ApiError, LinodeClient
66
from linode_api4.objects import (
7+
AlertDefinition,
78
MonitorDashboard,
89
MonitorMetricsDefinition,
910
MonitorService,
@@ -173,23 +174,14 @@ def test_integration_create_get_update_delete_alert_definition(
173174
assert created.id
174175
assert getattr(created, "label", None) == label
175176

176-
# Fetch by id
177-
fetched = client.monitor.get_alert_definitions(
178-
service_type=service_type, alert_id=created.id
179-
)
180-
assert fetched.id == created.id
181-
assert getattr(fetched, "label", None) == label
182-
183177
# Wait for server-side processing to complete (status transitions)
184178
timeout = 120
185179
interval = 10
186180
start = time.time()
187181
while getattr(created, "status", None) == "in progress" and (time.time() - start) < timeout:
188182
time.sleep(interval)
189183
try:
190-
created = client.monitor.alert_definitions(
191-
service_type=service_type, alert_id=created.id
192-
)
184+
created = client.load(AlertDefinition,created.id,service_type)
193185
except Exception:
194186
# transient errors while polling; continue until timeout
195187
pass
@@ -208,17 +200,18 @@ def test_integration_create_get_update_delete_alert_definition(
208200
finally:
209201
if created:
210202
# Best-effort cleanup; allow transient errors.
211-
alert_update_interval = 120 # max time alert should take to update
203+
alert_update_interval = 60 # max time alert should take to update
212204
try:
213205
time.sleep(alert_update_interval)
214-
client.monitor.delete_alert_definition(service_type, created.id)
206+
delete_alert = client.load(AlertDefinition,created.id,service_type)
207+
delete_alert.delete()
215208
except Exception:
216209

217210
pass
218211

219212
# confirm it's gone (if API returns 404 or raises)
220213
try:
221-
client.monitor.alert_definitions(service_type=service_type, alert_id=created.id)
214+
client.load(AlertDefinition,created.id,service_type)
222215
# If no exception, fail explicitly
223216
assert False, "Alert definition still retrievable after delete"
224217
except ApiError:

0 commit comments

Comments
 (0)