Skip to content

Commit dc2090d

Browse files
committed
TypeConfiguration support and handle resource id from v2.x.x format
1 parent ef2252b commit dc2090d

File tree

6 files changed

+245
-45
lines changed

6 files changed

+245
-45
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
{
2+
"properties": {
3+
"DatadogCredentials": {
4+
"$ref": "#/definitions/DatadogCredentials"
5+
}
6+
},
7+
"additionalProperties": false,
8+
"definitions": {
9+
"Creator": {
10+
"type": "object",
11+
"properties": {
12+
"Name": {
13+
"description": "Name of the creator of the monitor",
14+
"type": "string"
15+
},
16+
"Handle": {
17+
"description": "Handle of the creator of the monitor",
18+
"type": "string"
19+
},
20+
"Email": {
21+
"description": "Email of the creator of the monitor",
22+
"type": "string"
23+
}
24+
}
25+
},
26+
"MonitorThresholds": {
27+
"type": "object",
28+
"properties": {
29+
"Critical": {
30+
"description": "Threshold value for triggering an alert",
31+
"type": "number"
32+
},
33+
"CriticalRecovery": {
34+
"description": "Threshold value for recovering from an alert state",
35+
"type": "number"
36+
},
37+
"OK": {
38+
"description": "Threshold value for recovering from an alert state",
39+
"type": "number"
40+
},
41+
"Warning": {
42+
"description": "Threshold value for triggering a warning",
43+
"type": "number"
44+
},
45+
"WarningRecovery": {
46+
"description": "Threshold value for recovering from a warning state",
47+
"type": "number"
48+
}
49+
}
50+
},
51+
"MonitorThresholdWindows": {
52+
"type": "object",
53+
"properties": {
54+
"TriggerWindow": {
55+
"description": "How long a metric must be anomalous before triggering an alert",
56+
"type": "string"
57+
},
58+
"RecoveryWindow": {
59+
"description": "How long an anomalous metric must be normal before recovering from an alert state",
60+
"type": "string"
61+
}
62+
}
63+
},
64+
"MonitorOptions": {
65+
"type": "object",
66+
"properties": {
67+
"EnableLogsSample": {
68+
"description": "Whether or not to include a sample of the logs",
69+
"type": "boolean"
70+
},
71+
"EscalationMessage": {
72+
"description": "Message to include with a re-notification when renotify_interval is set",
73+
"type": "string"
74+
},
75+
"EvaluationDelay": {
76+
"description": "Time in seconds to delay evaluation",
77+
"type": "integer"
78+
},
79+
"IncludeTags": {
80+
"description": "Whether or not to include triggering tags into notification title",
81+
"type": "boolean"
82+
},
83+
"Locked": {
84+
"description": "Whether or not changes to this monitor should be restricted to the creator or admins",
85+
"type": "boolean"
86+
},
87+
"MinLocationFailed": {
88+
"description": "Number of locations allowed to fail before triggering alert",
89+
"type": "integer"
90+
},
91+
"NewHostDelay": {
92+
"description": "Time in seconds to allow a host to start reporting data before starting the evaluation of monitor results",
93+
"type": "integer"
94+
},
95+
"NoDataTimeframe": {
96+
"description": "Number of minutes data stopped reporting before notifying",
97+
"type": "integer"
98+
},
99+
"NotifyAudit": {
100+
"description": "Whether or not to notify tagged users when changes are made to the monitor",
101+
"type": "boolean"
102+
},
103+
"NotifyNoData": {
104+
"description": "Whether or not to notify when data stops reporting",
105+
"type": "boolean"
106+
},
107+
"RenotifyInterval": {
108+
"description": "Number of minutes after the last notification before the monitor re-notifies on the current status",
109+
"type": "integer"
110+
},
111+
"RequireFullWindow": {
112+
"description": "Whether or not the monitor requires a full window of data before it is evaluated",
113+
"type": "boolean"
114+
},
115+
"SyntheticsCheckID": {
116+
"description": "ID of the corresponding synthetics check",
117+
"type": "integer"
118+
},
119+
"Thresholds": {
120+
"description": "The threshold definitions",
121+
"$ref": "#/definitions/MonitorThresholds"
122+
},
123+
"ThresholdWindows": {
124+
"description": "The threshold window definitions",
125+
"$ref": "#/definitions/MonitorThresholdWindows"
126+
},
127+
"TimeoutH": {
128+
"description": "Number of hours of the monitor not reporting data before it automatically resolves",
129+
"type": "integer"
130+
}
131+
}
132+
},
133+
"DatadogCredentials": {
134+
"description": "Credentials for the Datadog API",
135+
"properties": {
136+
"ApiKey": {
137+
"description": "Datadog API key",
138+
"type": "string"
139+
},
140+
"ApplicationKey": {
141+
"description": "Datadog application key",
142+
"type": "string"
143+
},
144+
"ApiURL": {
145+
"description": "Datadog API URL (defaults to https://api.datadoghq.com) Use https://api.datadoghq.eu for EU accounts.",
146+
"type": "string"
147+
}
148+
},
149+
"required": [
150+
"ApiKey",
151+
"ApplicationKey"
152+
],
153+
"type": "object",
154+
"additionalProperties": false
155+
}
156+
},
157+
"typeName": "Datadog::Monitors::Monitor"
158+
}

datadog-monitors-monitor-handler/datadog-monitors-monitor.json

+24-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
{
22
"typeName": "Datadog::Monitors::Monitor",
33
"description": "Datadog Monitor 3.0.0",
4+
"typeConfiguration": {
5+
"properties": {
6+
"DatadogCredentials": {
7+
"$ref": "#/definitions/DatadogCredentials"
8+
}
9+
},
10+
"additionalProperties": false
11+
},
412
"definitions": {
513
"Creator": {
614
"type": "object",
@@ -125,9 +133,7 @@
125133
"type": "integer"
126134
}
127135
}
128-
}
129-
},
130-
"properties": {
136+
},
131137
"DatadogCredentials": {
132138
"description": "Credentials for the Datadog API",
133139
"properties": {
@@ -148,14 +154,27 @@
148154
"ApiKey",
149155
"ApplicationKey"
150156
],
151-
"type": "object"
157+
"type": "object",
158+
"additionalProperties": false
159+
}
160+
},
161+
"properties": {
162+
"DatadogCredentials": {
163+
"$ref": "#/definitions/DatadogCredentials"
152164
},
153165
"Creator": {
154166
"$ref": "#/definitions/Creator"
155167
},
156168
"Id": {
157169
"description": "ID of the monitor",
158-
"type": "integer"
170+
"oneOf": [
171+
{
172+
"type": "string"
173+
},
174+
{
175+
"type": "integer"
176+
}
177+
]
159178
},
160179
"Message": {
161180
"description": "A message to include with notifications for the monitor",
@@ -216,7 +235,6 @@
216235
}
217236
},
218237
"required": [
219-
"DatadogCredentials",
220238
"Query",
221239
"Type"
222240
],

datadog-monitors-monitor-handler/docs/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Properties:
4646

4747
Credentials for the Datadog API
4848

49-
_Required_: Yes
49+
_Required_: No
5050

5151
_Type_: <a href="datadogcredentials.md">DatadogCredentials</a>
5252

Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
git+https://github.com/datadog/datadog-cloudformation-resources.git@datadog-cloudformation-common-python-0.0.4#egg=datadog_cloudformation_common&subdirectory=datadog-cloudformation-common-python
1+
git+https://github.com/datadog/datadog-cloudformation-resources.git@datadog-cloudformation-common-python-0.0.6#egg=datadog_cloudformation_common&subdirectory=datadog-cloudformation-common-python

datadog-monitors-monitor-handler/src/datadog_monitors_monitor/handlers.py

+39-36
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import logging
2-
from typing import Any, MutableMapping, Optional
2+
from typing import Any, MutableMapping, Optional, Union, Tuple
33

44
from cloudformation_cli_python_lib import (
55
Action,
@@ -23,15 +23,17 @@
2323
from .models import Creator, MonitorOptions, MonitorThresholdWindows, \
2424
MonitorThresholds, \
2525
ResourceHandlerRequest, \
26-
ResourceModel
26+
ResourceModel, \
27+
DatadogCredentials, \
28+
TypeConfigurationModel
2729
from .version import __version__
2830

2931
# Use this logger to forward log messages to CloudWatch Logs.
3032
LOG = logging.getLogger(__name__)
3133
TYPE_NAME = "Datadog::Monitors::Monitor"
3234
TELEMETRY_TYPE_NAME = "monitors-monitor"
3335

34-
resource = Resource(TYPE_NAME, ResourceModel)
36+
resource = Resource(TYPE_NAME, ResourceModel, TypeConfigurationModel)
3537
test_entrypoint = resource.test_entrypoint
3638

3739

@@ -43,15 +45,11 @@ def read_handler(
4345
) -> ProgressEvent:
4446
LOG.info("Starting %s Read Handler", TYPE_NAME)
4547
model = request.desiredResourceState
46-
with v1_client(
47-
model.DatadogCredentials.ApiKey,
48-
model.DatadogCredentials.ApplicationKey,
49-
model.DatadogCredentials.ApiURL or "https://api.datadoghq.com",
50-
TELEMETRY_TYPE_NAME,
51-
__version__,
52-
) as api_client:
48+
49+
api_key, app_key, api_url = get_auth(model.DatadogCredentials, request.typeConfiguration)
50+
with v1_client(api_key, app_key, api_url, TELEMETRY_TYPE_NAME, __version__) as api_client:
5351
api_instance = MonitorsApi(api_client)
54-
monitor_id = model.Id
52+
monitor_id = get_id(model.Id)
5553
try:
5654
monitor = api_instance.get_monitor(monitor_id)
5755
except ApiException as e:
@@ -115,7 +113,7 @@ def read_handler(
115113
TriggerWindow=tw.trigger_window if hasattr(tw, "trigger_window") else None,
116114
RecoveryWindow=tw.recovery_window if hasattr(tw, "recovery_window") else None,
117115
)
118-
model.Id = monitor.id
116+
model.Id = get_id(monitor.id)
119117

120118
return ProgressEvent(
121119
status=OperationStatus.SUCCESS,
@@ -145,16 +143,11 @@ def update_handler(
145143
if options:
146144
monitor.options = options
147145

148-
with v1_client(
149-
model.DatadogCredentials.ApiKey,
150-
model.DatadogCredentials.ApplicationKey,
151-
model.DatadogCredentials.ApiURL or "https://api.datadoghq.com",
152-
TELEMETRY_TYPE_NAME,
153-
__version__,
154-
) as api_client:
146+
api_key, app_key, api_url = get_auth(model.DatadogCredentials, request.typeConfiguration)
147+
with v1_client(api_key, app_key, api_url, TELEMETRY_TYPE_NAME, __version__) as api_client:
155148
api_instance = MonitorsApi(api_client)
156149
try:
157-
api_instance.update_monitor(model.Id, monitor)
150+
api_instance.update_monitor(get_id(model.Id), monitor)
158151
except ApiException as e:
159152
LOG.error("Exception when calling MonitorsApi->update_monitor: %s\n", e)
160153
return ProgressEvent(
@@ -173,16 +166,11 @@ def delete_handler(
173166
LOG.info("Starting %s Delete Handler", TYPE_NAME)
174167
model = request.desiredResourceState
175168

176-
with v1_client(
177-
model.DatadogCredentials.ApiKey,
178-
model.DatadogCredentials.ApplicationKey,
179-
model.DatadogCredentials.ApiURL or "https://api.datadoghq.com",
180-
TELEMETRY_TYPE_NAME,
181-
__version__,
182-
) as api_client:
169+
api_key, app_key, api_url = get_auth(model.DatadogCredentials, request.typeConfiguration)
170+
with v1_client(api_key, app_key, api_url, TELEMETRY_TYPE_NAME, __version__) as api_client:
183171
api_instance = MonitorsApi(api_client)
184172
try:
185-
api_instance.delete_monitor(model.Id)
173+
api_instance.delete_monitor(get_id(model.Id))
186174
except ApiException as e:
187175
LOG.error("Exception when calling MonitorsApi->delete_monitor: %s\n", e)
188176
return ProgressEvent(
@@ -217,13 +205,8 @@ def create_handler(
217205
if options:
218206
monitor.options = options
219207

220-
with v1_client(
221-
model.DatadogCredentials.ApiKey,
222-
model.DatadogCredentials.ApplicationKey,
223-
model.DatadogCredentials.ApiURL or "https://api.datadoghq.com",
224-
TELEMETRY_TYPE_NAME,
225-
__version__,
226-
) as api_client:
208+
api_key, app_key, api_url = get_auth(model.DatadogCredentials, request.typeConfiguration)
209+
with v1_client(api_key, app_key, api_url, TELEMETRY_TYPE_NAME, __version__) as api_client:
227210
api_instance = MonitorsApi(api_client)
228211
try:
229212
monitor_resp = api_instance.create_monitor(monitor)
@@ -233,7 +216,7 @@ def create_handler(
233216
status=OperationStatus.FAILED, resourceModel=model, message=f"Error creating monitor: {e}"
234217
)
235218

236-
model.Id = monitor_resp.id
219+
model.Id = get_id(monitor_resp.id)
237220
return read_handler(session, request, callback_context)
238221

239222

@@ -298,3 +281,23 @@ def build_monitor_options_from_model(model: ResourceModel) -> ApiMonitorOptions:
298281
options.threshold_windows.recovery_window = model.Options.ThresholdWindows.RecoveryWindow
299282

300283
return options
284+
285+
286+
def get_id(_id: Union[str, int]) -> int:
287+
if isinstance(_id, str):
288+
return int(float(_id))
289+
return _id
290+
291+
292+
def get_auth(
293+
dd_credentials: Optional[DatadogCredentials],
294+
type_configuration: Optional[TypeConfigurationModel]
295+
) -> Tuple[str, str, str]:
296+
if dd_credentials:
297+
return dd_credentials.ApiKey, \
298+
dd_credentials.ApplicationKey, \
299+
dd_credentials.ApiURL or "https://api.datadoghq.com"
300+
else:
301+
return type_configuration.DatadogCredentials.ApiKey, \
302+
type_configuration.DatadogCredentials.ApplicationKey, \
303+
type_configuration.DatadogCredentials.ApiURL or "https://api.datadoghq.com"

0 commit comments

Comments
 (0)